#include #include #define FCPP_ENABLE_LAMBDA #include "prelude.h" namespace TL = fcpp::fcpp_lambda; // Typelists #include using fcpp::IRef; using fcpp::List; ////////////////////////////////////////////////////////////////////// // Macros which are helpful to our clients #define FUN1(functor,arg1t) \ struct functor : public lcpp::Functor { \ static const char * const name; \ } functor; \ const char * const functor::name = #functor; #define FUN2(functor,arg1t,arg2t) \ struct functor : public lcpp::Functor { \ static const char * const name; \ } functor; \ const char * const functor::name = #functor; #define FUN3(functor,arg1t,arg2t,arg3t) \ struct functor : public lcpp::Functor { \ static const char * const name; \ } functor; \ const char * const functor::name = #functor; #define DECLARE(name,type,num) \ typedef lcpp::LogicVariable name ## _TYPE; \ const name ## _TYPE& name = name ## _TYPE::instance( #name ); namespace lcpp { namespace impl { ////////////////////////////////////////////////////////////////////// // Set RTDEBUG to the name of a stream (like std::cout) to print // run-time debugging info (similar to prolog's trace command). Every // run() method (and also ImplicationStorage::go()) are instrumented // with RTDEBUGn calls. int indent = 0; void RTDEBUG1( const char *s ) { (void) s; #ifdef RTDEBUG for(int i=0;i const T& RTDEBUG2( const T& x ) { #ifdef RTDEBUG indent--; #endif return x; } ////////////////////////////////////////////////////////////////////// // Set DEBUGENV to a stream (like std::cout) to get debugging on // environment creation. void DEBUGENV1( const char* s ) { (void) s; #ifdef DEBUGENV DEBUGENV << s << std::endl; #endif } ////////////////////////////////////////////////////////////////////// // Inheritance tests struct Funky {}; // "Functor"ness struct HasLV {}; // Reps which may contain LogicVariables inside them struct RepShape {}; // Reps which are Shapes ////////////////////////////////////////////////////////////////////// struct DontCare; // For _ (underscore) struct Empty { // For "unused" 2nd/3rd slots in a functor bool operator==( Empty ) const { return true; } }; ////////////////////////////////////////////////////////////////////// template struct HavingShapeAtom; template struct AtomImpl; template struct HavingShapeFunctor; // Term, Unifiable template struct FunctorImpl; // HS, unify(), argN(), template struct Functor; // Funky, operator() for clients struct Term; template struct Database; template class AtomFacade; template class FunctorFacade; template struct FunctorHelper; ////////////////////////////////////////////////////////////////////// // Various useful type computers template struct LVHelper { typedef TL::NIL LVs; }; template struct LVHelper { typedef typename DS::LVs LVs; }; template struct LV { typedef typename LVHelper::value>::LVs LVs; }; template struct ForceHelper { typedef DS Type; }; template struct ForceHelper { typedef typename DS::Shape Type; }; template struct Force { typedef typename ForceHelper::value>::Type Shape; }; template struct HavingShapeHelper { typedef HavingShapeAtom Type; typedef AtomImpl ImplType; typedef AtomFacade FacadeType; }; template struct HavingShapeHelper > { typedef HavingShapeFunctor Type; typedef FunctorImpl ImplType; typedef FunctorFacade FacadeType; }; template struct HavingShape { typedef typename Force::Shape Shape; typedef typename HavingShapeHelper::Type Type; typedef typename HavingShapeHelper::ImplType ImplType; typedef typename HavingShapeHelper::FacadeType FacadeType; }; template struct UnRepHelper { typedef Rep DS; }; template struct UnRepHelper { typedef typename Rep::DS DS; }; template struct UnRep { typedef typename UnRepHelper::value>::DS DS; }; template struct Environment; namespace Rep { template struct AddEnv; } template struct RepToImpl { typedef IRef > IE; typedef typename Rep::AddEnv::Result IRef_of_Impl; typedef typename IRef_of_Impl::WrappedType Result; }; template struct QueryResultType; ////////////////////////////////////////////////////////////////////// // Compile-time error checking template struct EnsureSameShapeHelper; template struct EnsureSameShapeHelper { static void go() {} }; template struct EnsureSameShape { typedef typename HavingShape::DS>::Shape AA; typedef typename HavingShape::DS>::Shape BB; static void go() { EnsureSameShapeHelper::go(); } }; template struct EnsureTermHelper; template struct EnsureTermHelper { static void go() {} }; template struct EnsureTermHelper {}; template struct EnsureTerm { typedef typename RepToImpl::Result U; static void go() { EnsureTermHelper::value,U>::go(); } }; template struct EnsureFunctorHelper; template <> struct EnsureFunctorHelper { static void go() {} }; template struct EnsureFunctor { typedef typename UnRep::DS T; static void go() { EnsureFunctorHelper::value>::go(); } }; ////////////////////////////////////////////////////////////////////// /* In the initial expression template tree, we use the FooRep classes to represent LC++ structures. Primitive types (like "int") and the LogicVariable type are the only types whose name doesn't end in "Rep" that should appear in such a structure. The Reps live in their own namespace to facilitate their constructors. == and && and || and not() and -= and Functor::operator() are the constructors for the Rep classes that clients use to construct queries. Later, we collect a whole LC++ term, create an environment, and call addEnv() to transform the "Rep" into an "Impl". That is, FooReps become FooImpls, primitives (e.g. "int") become AtomImpls, and LogicVariables become Bindings. These Impl classes have methods like unify() and run() and refer to each other via IRefs instead of member variables. */ ////////////////////////////////////////////////////////////////////// // Forward decls of Impl classes template class AtomImpl; template class Binding; template class UnificationTermImpl; class SucceedImpl; class DisjunctImpl; class ConjunctImpl; class NotProvableImpl; template class ImplicationImpl; template struct IsTermImpl; // Forward decl of the magic "Expr" class used by LogicVariable::is() template struct Expr; template struct ExprResult; namespace Rep { template struct LogicVariable; template struct FunctorRep; template struct IsTermRep; template struct UnificationTermRep; template struct DisjunctRep; template struct ConjunctRep; template struct NotProvableRep; template struct ImplicationRep; template struct DontCareLVRep : public RepShape { typedef S DS; typedef TL::NIL LVs; DontCareLVRep( const DontCare& ) {} }; template class LogicVariable : public HasLV, public RepShape { public: typedef S DS; typedef TL::CONS LVs; // FIX THIS: private LogicVariable( const LogicVariable& x ) : name_(x.name_) {} private: char *name_; LogicVariable( char *n ) : name_(n) {} // make all the Reps be friends so they can copy LVs template friend struct FunctorRep; template friend struct IsTermRep; template friend struct UnificationTermRep; template friend struct DisjunctRep; template friend struct ConjunctRep; template friend struct NotProvableRep; template friend struct ImplicationRep; template friend struct FunctorHelper; public: static LogicVariable instance( char* n ) { return LogicVariable(n); } char *name() const { return name_; } template IsTermRep,typename ExprResult::Type> is( const F&, const X&, const Y& ) const; template IsTermRep,typename ExprResult::Type> is( const F&, const X& ) const; template IsTermRep,typename ExprResult::Type> is( const F& ) const; }; struct SucceedRep {}; struct FailRep {}; template struct UnificationTermRep : public HasLV { typedef typename TL::AppendList::LVs, typename LV::LVs>::Result LVs; LHS lhs; RHS rhs; UnificationTermRep( const LHS& l, const RHS& r ) : lhs(l), rhs(r) {} }; template struct FunctorRep : public HasLV, public RepShape { typedef Self DS; typedef typename TL::AppendList::LVs, typename TL::AppendList::LVs, typename LV::LVs>::Result>::Result LVs; A1 a1; A2 a2; A3 a3; FunctorRep( const A1& b1, const A2& b2, const A3& b3 ) : a1(b1), a2(b2), a3(b3) {} }; template struct DisjunctRep : public HasLV { typedef typename TL::AppendList::LVs, typename LV::LVs>::Result LVs; LHS lhs; RHS rhs; DisjunctRep( const LHS& l, const RHS& r ) : lhs(l), rhs(r) {} }; template struct ConjunctRep : public HasLV { typedef typename TL::AppendList::LVs, typename LV::LVs>::Result LVs; LHS lhs; RHS rhs; ConjunctRep( const LHS& l, const RHS& r ) : lhs(l), rhs(r) {} }; template struct NotProvableRep : public HasLV { typedef typename LV::LVs LVs; X x; NotProvableRep( const X& xx ) : x(xx) {} }; template struct ImplicationRep : public HasLV { typedef typename TL::AppendList::LVs, typename LV::LVs>::Result LVs; LHS lhs; RHS rhs; ImplicationRep( const LHS& l, const RHS& r ) : lhs(l), rhs(r) {} }; template UnificationTermRep operator==( const A& a, const B& b ) { EnsureSameShape::go(); return UnificationTermRep(a,b); } template ConjunctRep operator&&( const A& a, const B& b ) { EnsureTerm::go(); EnsureTerm::go(); return ConjunctRep(a,b); } template DisjunctRep operator||( const A& a, const B& b ) { EnsureTerm::go(); EnsureTerm::go(); return DisjunctRep(a,b); } template ImplicationRep operator-=( const A& a, const B& b ) { EnsureFunctor::go(); EnsureTerm::go(); return ImplicationRep(a,b); } template NotProvableRep not_provable( const X& x ) { EnsureTerm::go(); return NotProvableRep(x); } } // end namespace Rep using Rep::LogicVariable; struct DontCare { template Rep::IsTermRep::RT>, typename ExprResult::Type> is( const F&, const X&, const Y& ) const; template Rep::IsTermRep::RT>, typename ExprResult::Type> is( const F&, const X& ) const; template Rep::IsTermRep::RT>, typename ExprResult::Type> is( const F& ) const; }; ////////////////////////////////////////////////////////////////////// // Note: can probably make this more efficient by inheriting "rest". template class Environment,T> > { typedef LogicVariable H; mutable fcpp::RefCountType refC_; IRef > b; char *name; Environment rest; public: void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } Environment() : refC_(0), b( new Binding(1) ), name("") {} void set_name_at( const H&, char* n ) { name = n; } template void set_name_at( const LV& l, char* n ) { rest.set_name_at(l,n); } typename HavingShape::FacadeType at( const H& ) { return b->facade(); } template typename HavingShape::DS>::FacadeType at( const LV& l ) { return rest.at(l); } IRef > basic_at( const H& ) { return b; } template IRef::DS> > basic_at( const LV& l ) { return rest.basic_at(l); } void show(); }; template <> struct Environment { mutable fcpp::RefCountType refC_; public: void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } void show() {} }; template IRef > make_env() { return IRef >( new Environment ); } ////////////////////////////////////////////////////////////////////// struct UnRes { // Unification Result bool ok; fcpp::Fun0 undo; UnRes( fcpp::Fun0 f ) : ok(true), undo(f) {} UnRes( bool b ) : ok(b), undo( fcpp::NoOp() ) {} }; struct Term { mutable fcpp::RefCountType refC_; Term() : refC_(0) {} void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } virtual List run( IRef future ) = 0; // RTDEBUG virtual ~Term() {} }; template struct Unifiable { mutable fcpp::RefCountType refC_; Unifiable() : refC_(0) {} void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } typedef typename HavingShape::Type HS; typedef typename HavingShape::ImplType HSI; virtual UnRes unify( IRef other ) = 0; // for double-dispatch virtual UnRes unify2( Binding* it ) = 0; virtual UnRes unify2( HSI* it ) = 0; virtual ~Unifiable() {} }; ////////////////////////////////////////////////////////////////////// template struct HavingShapeAtom : public Unifiable { typedef HavingShapeAtom Type; typedef AtomImpl ImplType; virtual bool bound() = 0; virtual IRef value() = 0; virtual AtomFacade facade() = 0; }; template struct HavingShapeFunctor : public Term, public Unifiable { typedef typename HavingShape::Type Type; typedef typename HavingShape::ImplType ImplType; typedef X Arg1; typedef Y Arg2; typedef Z Arg3; using Term::incref; // inherited from both parents using Term::decref; virtual bool bound() = 0; virtual IRef value() = 0; virtual FunctorFacade facade() = 0; }; ////////////////////////////////////////////////////////////////////// // Forward decl template IRef makeTermFromFunctoid( const F& f ); struct FailImpl : public Term { List run( IRef ) { RTDEBUG1("FailImpl"); return RTDEBUG2(fcpp::NIL); } }; extern IRef it_fail; // IRef "fail" struct EndOfQuery : public Term { List run( IRef ) { RTDEBUG1("EndOfQuery"); return RTDEBUG2(fcpp::cons(Empty(),fcpp::NIL)); } }; extern IRef it_end_of_query; // IRef "end_of_query" template class AtomImpl : public HavingShapeAtom { T x; public: typedef typename HavingShape::Type HS; typedef typename HavingShape::ImplType HSI; AtomImpl( const T& xx ) : x(xx) {} UnRes unify( IRef other ) { return other->unify2(this); } UnRes unify2( HSI* other ) { return UnRes( x==other->x ); } UnRes unify2( Binding* other ) { return other->unify2(this); } bool bound() { return true; } IRef value() { return IRef(this); } T data() { return x; } AtomFacade facade() { return AtomFacade( this ); } }; template class Binding : public HavingShape::Type { typedef typename HavingShape::Type Super; public: typedef typename HavingShape::Type HS; private: using Super::incref; using Super::decref; bool from_lv; typedef typename HavingShape::ImplType HSI; IRef next; IRef data; // !next && !data --> unbound // !next && data --> bound next --> linked IRef bottom() { IRef tmp = IRef(this); while( tmp->next ) tmp = tmp->next; return tmp; } private: void unbind( bool f_lv ) { (void) f_lv; //if( f_lv ) { //std::cout << "undoing a binding" << std::endl; //} data = IRef(); next = IRef(); } UnRes bind( IRef r ) { if( bound() ) throw "trying to bound already-bound ref!"; //if( from_lv ) { //std::cout << "making a binding" << std::endl; //} IRef tmp = bottom(); tmp->next = r; fcpp::Fun0 fun = fcpp::curry2(fcpp::ptr_to_fun(&Binding::unbind),tmp,from_lv); return UnRes( fun ); } UnRes bind( IRef r ) { if( bound() ) throw "trying to bind already-bound Binding!"; //if( from_lv ) { //std::cout << "making a binding" << std::endl; //} IRef tmp = bottom(); tmp->data = r; fcpp::Fun0 fun = fcpp::curry2(fcpp::ptr_to_fun(&Binding::unbind),tmp,from_lv); return UnRes( fun ); } public: Binding() : from_lv(false), next(0), data(0) {} Binding(int) : from_lv(true), next(0), data(0) {} bool bound() { return bottom()->data; } UnRes unify( IRef other ) { return other->unify2(this); } UnRes unify2( Binding* other ) { if( !other->bound() ) { return other->bind( IRef >(this) ); } else if( !bound() ) { return bind( IRef >(other) ); } else { return bottom()->data->unify2( &*(other->bottom()->data) ); } } UnRes unify2( HSI* other ) { if( !bound() ) { return bind( IRef(other) ); } else { return bottom()->data->unify2( other ); } } // only applies if functor shape List run( IRef future ) { RTDEBUG1("binding"); if( !bound() ) throw "cannot use unbound LV as term in query"; return RTDEBUG2(bottom()->data->run(future)); } IRef value() { if( !bound() ) throw "unbound!!!"; return bottom()->data; } void* name() { return &*bottom(); } typename HavingShape::FacadeType facade() { typedef typename HavingShape::FacadeType FT; return FT( this ); } }; struct DummyTerm : public Term { List run( IRef ) { throw "I should never get run"; } }; template struct UnificationTermImpl : public Term { IRef lhs, rhs; List run( IRef future ) { RTDEBUG1("UnificationTermImpl, with lhs and rhs types:"); RTDEBUG3(typeid(*lhs).name()); RTDEBUG3(typeid(*rhs).name()); UnRes ur = lhs->unify(rhs); if( ur.ok ) { // FIX THIS: check all run() logic; I think maybe fixed now, but needs // testing using fcpp::cat; using fcpp::before; using fcpp::Const; using fcpp::OddList; return RTDEBUG2( cat( future->run( IRef(new DummyTerm) ), before(ur.undo,Const()(OddList())))); } else return RTDEBUG2(fcpp::NIL); } UnificationTermImpl( IRef l, IRef r ) : lhs(l), rhs(r) {} }; class SucceedImpl : public Term { List run( IRef future ) { RTDEBUG1("SucceedImpl"); return RTDEBUG2(future->run( IRef(new DummyTerm) )); } }; struct DisjunctImpl : public Term { IRef lhs, rhs; List run( IRef future ) { RTDEBUG1("DisjunctImpl"); // FIX THIS: isn't lazy, or something. I should probably be returning // OddLists throughout, or otherwise delaying some calls. Hmm. return RTDEBUG2(fcpp::cat( lhs->run(future), fcpp::curry2(fcpp::ptr_to_fun(&Term::run),rhs,future))); } DisjunctImpl( IRef l, IRef r ) : lhs(l), rhs(r) {} }; struct ConjunctImpl : public Term { IRef lhs, rhs; List run( IRef future ) { RTDEBUG1("ConjunctImpl"); future = IRef( new ConjunctImpl( rhs, future ) ); return RTDEBUG2(lhs->run( future )); } ConjunctImpl( IRef l, IRef r ) : lhs(l), rhs(r) {} }; template class FunctorImpl : public HavingShapeFunctor { IRef > a1; IRef > a2; IRef > a3; public: typedef typename HavingShape::Type HS; typedef typename HavingShape::ImplType HSI; List run( IRef future ) { RTDEBUG1(Self::name); return RTDEBUG2(Database::makeTerm( IRef(this))->run(future)); } UnRes unify( IRef other ) { return other->unify2(this); } UnRes unify2( Binding* other ) { return other->unify2(this); } UnRes unify2( HSI* other ) { typedef IRef::Type> AA; typedef IRef::Type> BB; typedef IRef::Type> CC; UnRes x = other->a1->unify( AA(a1) ); if( x.ok ) { UnRes y = other->a2->unify( BB(a2) ); if( y.ok ) { UnRes z = other->a3->unify( CC(a3) ); if( z.ok ) { return UnRes( fcpp::before(z.undo, fcpp::before(y.undo,x.undo)) ); } else { y.undo(); x.undo(); } } else { x.undo(); } } return UnRes(false); } typedef typename HavingShape::Type B1; typedef typename HavingShape::Type B2; typedef typename HavingShape::Type B3; FunctorImpl( IRef x, IRef y, IRef z ) : a1( new Binding ), a2( new Binding ), a3( new Binding ) { a1->unify(x); a2->unify(y); a3->unify(z); } bool bound() { return true; } IRef value() { return IRef(this); } IRef > arg1() { return a1; } IRef > arg2() { return a2; } IRef > arg3() { return a3; } FunctorFacade facade() { return FunctorFacade( this ); } }; struct NotProvableImpl : public Term { IRef x; List run( IRef future ) { RTDEBUG1("NotProvableImpl"); List l = x->run( it_end_of_query ); if( l==fcpp::NIL ) return RTDEBUG2(future->run( IRef(new DummyTerm) )); while(l) l = fcpp::tail(l); return RTDEBUG2(fcpp::NIL); } NotProvableImpl( IRef l ) : x(l) {} }; template class ImplicationImpl { mutable fcpp::RefCountType refC_; public: void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } IRef lhs; IRef rhs; ImplicationImpl( IRef l, IRef r ) : lhs(l), rhs(r) {} }; ////////////////////////////////////////////////////////////////////// namespace Rep { template // N explicit: call addEnv(e,r) typename AddEnv::Result addEnv( const Env& e, const Rep& r ) { return AddEnv::go(e,r); } // N is iNcoming next-avail-LV-#, O is Outgoing next-avail-LV-# template struct AddEnv { static const int O = N; typedef IRef > Result; static Result go( const Env&, const Rep& r ) { DEBUGENV1("AddEnv Atom"); Result res = Result( new AtomImpl(r) ); DEBUGENV1("AddEnv Atom end"); return res; } }; template struct AddEnv,N> { static const int O = N-1; typedef DontCareLVRep Rep; typedef IRef > Result; static Result go( const Env&, const Rep& ) { DEBUGENV1("AddEnv DontCareLVRep"); Result res = Result( new Binding ); DEBUGENV1("AddEnv DontCareLVRep end"); return res; } }; template struct AddEnv { static const int O = N; typedef SucceedRep Rep; typedef IRef Result; static Result go( const Env&, const Rep& ) { DEBUGENV1("AddEnv SucceedImpl"); Result res = Result( new SucceedImpl ); DEBUGENV1("AddEnv SucceedImpl end"); return res; } }; template struct AddEnv { static const int O = N; typedef FailRep Rep; typedef IRef Result; static Result go( const Env&, const Rep& ) { DEBUGENV1("AddEnv FailImpl"); Result res = Result( new FailImpl ); DEBUGENV1("AddEnv FailImpl end"); return res; } }; template struct AddEnv,N > { static const int O = N; typedef LogicVariable Rep; typedef IRef > Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv LV"); Result res = e->basic_at(r); e->set_name_at(r,r.name()); DEBUGENV1("AddEnv LV end"); return res; } }; template struct AddEnv,N > { static const int tmp = AddEnv::O; static const int O = AddEnv::O; typedef UnificationTermRep Rep; typedef IRef Result; typedef typename AddEnv::Result::WrappedType LHSI; typedef typename LHSI::HS LHSS; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv UnificationTermImpl"); Result res = Result( new UnificationTermImpl( IRef( addEnv(e,r.lhs) ), IRef( addEnv(e,r.rhs) )) ); DEBUGENV1("AddEnv UnificationTermImpl end"); return res; } }; template struct AddEnv,N > { static const int t1 = AddEnv::O; static const int t2 = AddEnv::O; static const int O = AddEnv::O; typedef FunctorRep Rep; typedef typename UnRep::DS AA1; typedef typename UnRep::DS AA2; typedef typename UnRep::DS AA3; typedef typename HavingShape::Shape B1; typedef typename HavingShape::Shape B2; typedef typename HavingShape::Shape B3; typedef IRef > Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv FunctorImpl"); IRef::DS>::Type> b1( addEnv(e,r.a1) ); IRef::DS>::Type> b2( addEnv(e,r.a2) ); IRef::DS>::Type> b3( addEnv(e,r.a3) ); Result res = Result( new FunctorImpl(b1,b2,b3) ); DEBUGENV1("AddEnv FunctorImpl end"); return res; } }; template struct AddEnv,N > { static const int tmp = AddEnv::O; static const int O = AddEnv::O; typedef ConjunctRep Rep; typedef IRef Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv ConjunctImpl"); Result res = Result( new ConjunctImpl( IRef( addEnv(e,r.lhs) ), IRef( addEnv(e,r.rhs) ) ) ); DEBUGENV1("AddEnv ConjunctImpl end"); return res; } }; template struct AddEnv,N > { static const int tmp = AddEnv::O; static const int O = AddEnv::O; typedef DisjunctRep Rep; typedef IRef Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv DisjunctImpl"); Result res = Result( new DisjunctImpl( IRef( addEnv(e,r.lhs) ), IRef( addEnv(e,r.rhs) ) ) ); DEBUGENV1("AddEnv DisjunctImpl end"); return res; } }; template struct AddEnv,N > { static const int O = AddEnv::O; typedef NotProvableRep Rep; typedef IRef Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv NotProvableRep"); Result res = Result( new NotProvableImpl( IRef( addEnv(e,r.x) ) ) ); DEBUGENV1("AddEnv NotProvableRep end"); return res; } }; template struct AddEnv,N > { static const int tmp = AddEnv::O; static const int O = AddEnv::O; typedef ImplicationRep Rep; typedef typename AddEnv::Result::WrappedType LHSI; typedef typename LHSI::HS LHSS; typedef IRef > Result; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv ImplicationImpl"); Result res = Result( new ImplicationImpl( IRef( addEnv(e,r.lhs) ), IRef( addEnv(e,r.rhs) ) ) ); DEBUGENV1("AddEnv ImplicationImpl end"); return res; } }; } // end namespace Rep ////////////////////////////////////////////////////////////////////// template class TermFromFunctoid : public Term { F fxn; public: TermFromFunctoid( const F& ff ) : fxn(ff) {} List run( IRef future ) { RTDEBUG1("TermFromFunctoid"); return RTDEBUG2(fxn(future)); } }; template IRef makeTermFromFunctoid( const F& f ) { return IRef( new TermFromFunctoid(f) ); } template struct ImplicationI { mutable fcpp::RefCountType refC_; ImplicationI() : refC_(0) {} void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } virtual List go( IRef lhs_val, IRef future ) = 0; virtual ~ImplicationI() {} }; template struct Database > { typedef HavingShapeFunctor HS; static std::vector > > database; static void add( IRef > r ) { database.push_back(r); } static IRef makeTerm( IRef lhs_val ) { typedef typename std::vector > >::reverse_iterator Iter; IRef t = it_fail; for( Iter i = database.rbegin(); i != database.rend(); ++i ) { IRef temp = makeTermFromFunctoid( fcpp::curry3( fcpp::ptr_to_fun(&ImplicationI::go), *i, lhs_val ) ); t = IRef( new DisjunctImpl( temp, t ) ); } return t; } }; template std::vector > > > Database >::database; template class ImplicationStorage : public ImplicationI { Rep::ImplicationRep rep; public: ImplicationStorage( const Rep::ImplicationRep& r ) : rep(r) {} List go( IRef lhs_val, IRef future ) { typedef typename Rep::ImplicationRep R; typedef typename QueryResultType::IE IE; typedef typename QueryResultType::SLVL SLVL; IE e = make_env(); IRef > ii = Rep::addEnv<-1>(e,rep); typedef UnificationTermImpl UT; IRef t( new UT( ii->lhs, lhs_val ) ); t = IRef( new ConjunctImpl( t, ii->rhs ) ); RTDEBUG1("impl storage go()"); return RTDEBUG2(t->run(future)); } }; ////////////////////////////////////////////////////////////////////// // Meta-programming for static analysis stuff template struct Ctr {}; template struct Update; template struct Update,TCL>,LogicVariable > { typedef TL::CONS,TCL> Result; }; template struct Update,E> { typedef TL::CONS::Result> Result; }; template struct Update > { typedef TL::CONS,TL::NIL> Result; }; template struct CountH; template struct CountH { typedef Acc Result; }; template struct CountH,Acc> { typedef typename CountH::Result>::Result Result; }; template struct Count { typedef typename CountH::Result Result; }; template struct LogicVar { static void UsedOnlyOnceIn_lassert_() { int x = 3; } }; template struct Warn; template struct Warn,T> > { Warn() { LogicVar::UsedOnlyOnceIn_lassert_(); } Warn x; }; template struct Warn,T> > { Warn x; }; template <> struct Warn {}; template void lassert( Rep::ImplicationRep ir ) { // Static analysis (check for one-time-use vars) typedef typename LV >::LVs LVs; typedef typename Count::Result Counted; typedef Warn W; W w; (void) w; // Do the work typedef typename HavingShape::DS>::Type HS; IRef > r( new ImplicationStorage(ir) ); Database::add( r ); } template void lassert( T x ) { lassert( x -= Rep::SucceedRep() ); } ////////////////////////////////////////////////////////////////////// template struct IfDontCare { typedef X Result; }; template struct IfDontCare { typedef Rep::DontCareLVRep Result; }; template struct FunctorHelper { typedef typename IfDontCare::Result B1; typedef typename IfDontCare::Result B2; typedef typename IfDontCare::Result B3; typedef Rep::FunctorRep Result; static Result go( const BB1& b1, const BB2& b2, const BB3& b3 ) { EnsureSameShape::go(); EnsureSameShape::go(); EnsureSameShape::go(); return Rep::FunctorRep( B1(b1), B2(b2), B3(b3) ); } }; template struct Functor : public Funky { typedef Functor Shape; typedef DontCare DC; typedef A1 Arg1; typedef A2 Arg2; typedef A3 Arg3; template typename FunctorHelper::Result operator()( const B1& b1, const B2& b2, const B3& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const B1& b1, const B2& b2, const DC& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const B1& b1, const DC& b2, const B3& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const DC& b1, const B2& b2, const B3& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const B1& b1, const DC& b2, const DC& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const DC& b1, const B2& b2, const DC& b3 ) { return FunctorHelper::go(b1,b2,b3); } template typename FunctorHelper::Result operator()( const DC& b1, const DC& b2, const B3& b3 ) { return FunctorHelper::go(b1,b2,b3); } typename FunctorHelper::Result operator()( const DC& b1, const DC& b2, const DC& b3 ) { return FunctorHelper::go(b1,b2,b3); } }; template struct Functor : public Funky { typedef Functor Shape; typedef DontCare DC; typedef Empty EM; typedef A1 Arg1; typedef A2 Arg2; typedef Empty Arg3; template typename FunctorHelper::Result operator()( const B1& b1, const B2& b2 ) { return FunctorHelper::go(b1,b2,Empty()); } template typename FunctorHelper::Result operator()( const B1& b1, const DC& b2 ) { return FunctorHelper::go(b1,b2,Empty()); } template typename FunctorHelper::Result operator()( const DC& b1, const B2& b2 ) { return FunctorHelper::go(b1,b2,Empty()); } typename FunctorHelper::Result operator()( const DC& b1, const DC& b2 ) { return FunctorHelper::go(b1,b2,Empty()); } }; template struct Functor : public Funky { typedef Functor Shape; typedef DontCare DC; typedef Empty EM; typedef A1 Arg1; typedef Empty Arg2; typedef Empty Arg3; template typename FunctorHelper::Result operator()( const B1& b1 ) { return FunctorHelper::go(b1,Empty(),Empty()); } typename FunctorHelper::Result operator()( const DC& b1 ) { return FunctorHelper::go(b1,Empty(),Empty()); } }; ////////////////////////////////////////////////////////////////////// // Meta-programming for sorting/unique-ing a list of LVs that appear in // a term. template struct IfThen { typedef T Result; }; template struct IfThen { typedef F Result; }; struct ErrorAllLVTypesMustHaveDistinctIntegers {}; template struct InsertInOrder; template struct InsertInOrder { typedef TL::CONS Result; }; template struct InsertInOrder,TL::CONS,Rest> > { typedef typename IfThen<(j,TL::CONS,Rest> >, typename IfThen<(j>i), TL::CONS, typename InsertInOrder,Rest>::Result>, ErrorAllLVTypesMustHaveDistinctIntegers>::Result>::Result Result; }; template struct SortLVsHelper; template struct SortLVsHelper { typedef SLVL Result; }; template struct SortLVsHelper,Rest>,SLVL> { typedef typename InsertInOrder,SLVL>::Result Temp; typedef typename SortLVsHelper::Result Result; }; template struct SortLVs { typedef typename SortLVsHelper::Result Result; }; template struct QRTH { // Query Result Type Helper (from Logic Var List) typedef typename SortLVs::Result SLVL; typedef IRef > IE; // IRef typedef std::pair > Result; }; // QRT gives users an easy way to get type of environment. template struct QRT { typedef TL::CONS > > > > L; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; template struct QRT { typedef TL::CONS > > > L; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; template struct QRT { typedef TL::CONS > > L; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; template struct QRT { typedef TL::CONS > L; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; template struct QRT { typedef TL::CONS L; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; // FIX THIS: the RemoveDuplicates in TL doesn't work for some unknown // reason, so I use my own version here. See if TL::RemoveDuplicates is // broken for FC++ some time. template struct RemoveDuplicates; template struct RemoveDuplicatesHelp; template struct RemoveDuplicatesHelp,true> { typedef TL::CONS::Result> Result; }; template struct RemoveDuplicatesHelp,false> { typedef typename RemoveDuplicates::Result Result; }; template struct RemoveDuplicates; template <> struct RemoveDuplicates { typedef TL::NIL Result; }; template struct RemoveDuplicates > { typedef typename RemoveDuplicatesHelp, !(TL::Contains::value)>::Result Result; }; template struct QueryResultType { typedef typename Q::LVs LL; typedef typename RemoveDuplicates::Result L; typedef typename QRTH::SLVL SLVL; typedef typename QRTH::IE IE; typedef typename QRTH::Result Result; }; ////////////////////////////////////////////////////////////////////// template typename QueryResultType::Result query( const R& someTermRep ) { typedef typename QueryResultType::IE IE; typedef typename QueryResultType::SLVL SLVL; IE e = make_env(); typename Rep::AddEnv::Result t = Rep::addEnv<-1>( e, someTermRep ); List l = fcpp::curry2( fcpp::ptr_to_fun(&Term::run), t, it_end_of_query ); return std::make_pair( e, l ); } template List::IE> lquery( const R& someTermRep ) { typedef typename QueryResultType::IE IE; std::pair > p = query(someTermRep); return fcpp::curry2(fcpp::map,fcpp::ignore(fcpp::const_(p.first)),p.second); } template void Environment,T> >::show() { const LogicVariable& lv = LogicVariable::instance(0); //std::cout << " - LV #" << i << " (" << typeid(S).name() << ") \t= "; std::cout << " - " << this->name << "\t= "; std::cout << this->at( lv ) << std::endl; this->rest.show(); } template void iquery( const R& someTermRep ) { typedef typename QueryResultType::IE IE; std::pair > p = query(someTermRep); int i = 1; while( p.second ) { std::cout << "Result #" << i << std::endl; ++i; p.first->show(); p.second = fcpp::tail( p.second ); } } ////////////////////////////////////////////////////////////////////// // Expr and is() support // In order to store a value in an LC++ object, the value needs to // support == (for unification tests). Functoids don't, so we wrap them. template struct Opaque { typedef Functoid F; F f; Opaque( const F& ff ) : f(ff) {} bool operator==( const Opaque& ) const { return false; } }; template Opaque opaque( const Functoid& f ) { return Opaque(f); } template struct Expr : public Functor,F,X,Y> { static const char * const name; }; template const char * const Expr::name = "expr"; template struct ExprResult { typedef typename UnRep >::DS FS; typedef typename FS::F FF; typedef typename UnRep::DS XS; typedef typename UnRep::DS YS; typedef Rep::FunctorRep,Opaque,X,Y> Type; typedef typename fcpp::RT::ResultType RT; }; template struct ExprResult { typedef typename UnRep >::DS FS; typedef typename FS::F FF; typedef typename UnRep::DS XS; typedef Rep::FunctorRep,Opaque,X> Type; typedef typename fcpp::RT::ResultType RT; }; template struct ExprResult { typedef typename UnRep >::DS FS; typedef typename FS::F FF; typedef Rep::FunctorRep,Opaque > Type; typedef typename fcpp::RT::ResultType RT; }; template typename ExprResult::Type expr( const F& f, const X& x, const Y& y ) { typedef typename UnRep >::DS FS; typedef typename UnRep::DS XS; typedef typename UnRep::DS YS; return Expr()(opaque(f),x,y); } template typename ExprResult::Type expr( const F& f, const X& x ) { typedef typename UnRep >::DS FS; typedef typename UnRep::DS XS; return Expr()(opaque(f),x); } template typename ExprResult::Type expr( const F& f ) { typedef typename UnRep >::DS FS; return Expr()(opaque(f)); } namespace Rep { template struct IsTermRep : public HasLV { typedef LR LHS; typedef FR RHS; typedef typename TL::AppendList::LVs, typename LV::LVs>::Result LVs; LHS lhs; RHS rhs; IsTermRep( const LHS& l, const RHS& r ) : lhs(l), rhs(r) {} }; template struct AddEnv,N > { typedef LR LHSR; typedef FR RHSR; static const int tmp = AddEnv::O; static const int O = AddEnv::O; typedef IsTermRep Rep; typedef IRef Result; typedef typename AddEnv::Result::WrappedType LHSI; typedef typename LHSI::HS LHSS; typedef typename HavingShape::Type RHSS; static Result go( const Env& e, const Rep& r ) { DEBUGENV1("AddEnv IsTermImpl"); typedef typename FR::DS::Arg2 X; typedef typename FR::DS::Arg3 Y; Result res = Result( new IsTermImpl( IRef( addEnv(e,r.lhs) ), IRef( addEnv(e,r.rhs) )) ); DEBUGENV1("AddEnv IsTermImpl end"); return res; } }; } template struct IsTermImpl : public Term { IRef b; IRef efxy; IsTermImpl( const IRef& l, const IRef& r ) : b(l), efxy(r) {} List run( IRef future ) { RTDEBUG1("IsTermImpl"); if( !efxy->bound() ) return RTDEBUG2(fcpp::NIL); if( !efxy->value()->arg1()->bound() ) return RTDEBUG2(fcpp::NIL); if( !efxy->value()->arg2()->bound() ) return RTDEBUG2(fcpp::NIL); if( !efxy->value()->arg3()->bound() ) return RTDEBUG2(fcpp::NIL); typedef typename fcpp::RT::ResultType R; R r = efxy->value()->arg1()->value()->data().f( efxy->value()->arg2()->value()->data(), efxy->value()->arg3()->value()->data() ); IRef > ir( new AtomImpl(r) ); // Note: one of few cases where we don't need to create a Term // on the heap in an IRef. We just want to call .run() is all. UnificationTermImpl uti( b, ir ); return RTDEBUG2(uti.run(future)); } }; template struct IsTermImpl : public Term { IRef b; IRef efx; IsTermImpl( const IRef& l, const IRef& r ) : b(l), efx(r) {} List run( IRef future ) { RTDEBUG1("IsTermImpl"); if( !efx->bound() ) return RTDEBUG2(fcpp::NIL); if( !efx->value()->arg1()->bound() ) return RTDEBUG2(fcpp::NIL); if( !efx->value()->arg2()->bound() ) return RTDEBUG2(fcpp::NIL); typedef typename fcpp::RT::ResultType R; R r = efx->value()->arg1()->value()->data().f( efx->value()->arg2()->value()->data() ); IRef > ir( new AtomImpl(r) ); // Note: one of few cases where we don't need to create a Term // on the heap in an IRef. We just want to call .run() is all. UnificationTermImpl uti( b, ir ); return RTDEBUG2(uti.run(future)); } }; template struct IsTermImpl : public Term { IRef b; IRef ef; IsTermImpl( const IRef& l, const IRef& r ) : b(l), ef(r) {} List run( IRef future ) { RTDEBUG1("IsTermImpl"); if( !ef->bound() ) return RTDEBUG2(fcpp::NIL); if( !ef->value()->arg1()->bound() ) return RTDEBUG2(fcpp::NIL); typedef typename fcpp::RT::ResultType R; R r = ef->value()->arg1()->value()->data().f(); IRef > ir( new AtomImpl(r) ); // Note: one of few cases where we don't need to create a Term // on the heap in an IRef. We just want to call .run() is all. UnificationTermImpl uti( b, ir ); return RTDEBUG2(uti.run(future)); } }; ////////////////////////////////////////////////////////////////////// // is() namespace Rep { template template IsTermRep,typename ExprResult::Type> LogicVariable::is( const F& f, const X& x, const Y& y ) const { return IsTermRep, typename ExprResult::Type>( *this, expr(f,x,y) ); } template template IsTermRep,typename ExprResult::Type> LogicVariable::is( const F& f, const X& x ) const { return IsTermRep, typename ExprResult::Type>( *this, expr(f,x) ); } template template IsTermRep,typename ExprResult::Type> LogicVariable::is( const F& f ) const { return IsTermRep, typename ExprResult::Type>( *this, expr(f) ); } } template Rep::IsTermRep::RT>, typename ExprResult::Type> DontCare::is( const F& f, const X& x, const Y& y ) const { typedef Rep::DontCareLVRep::RT> DCLVR; return Rep::IsTermRep::Type> ( DCLVR(*this), expr(f,x,y) ); } template Rep::IsTermRep::RT>, typename ExprResult::Type> DontCare::is( const F& f, const X& x ) const { typedef Rep::DontCareLVRep::RT> DCLVR; return Rep::IsTermRep::Type> ( DCLVR(*this), expr(f,x) ); } template Rep::IsTermRep::RT>, typename ExprResult::Type> DontCare::is( const F& f ) const { typedef Rep::DontCareLVRep::RT> DCLVR; return Rep::IsTermRep::Type> ( DCLVR(*this), expr(f) ); } ////////////////////////////////////////////////////////////////////// // Facades template class AtomFacade { IRef< HavingShapeAtom > x; public: AtomFacade( HavingShapeAtom* p ) : x(p) {} operator bool() const { return x->bound(); } T operator*() const { return x->value()->data(); } void* name() const { return dynamic_cast*>( &*x )->name(); } }; template std::ostream& operator<<( std::ostream& o, const AtomFacade& af ) { if( af ) return o << *af; else return o << "_" << af.name(); } template class FunctorValue { IRef< FunctorImpl > x; public: FunctorValue( FunctorImpl* p ) : x(p) {} typename HavingShape::FacadeType arg1() { return x->arg1()->facade(); } typename HavingShape::FacadeType arg2() { return x->arg2()->facade(); } typename HavingShape::FacadeType arg3() { return x->arg3()->facade(); } }; template struct OperatorRightArrowProxy { T x; OperatorRightArrowProxy( const T& xx ) : x(xx) {} T* operator->() { return &x; } }; template class FunctorFacade { IRef< HavingShapeFunctor > x; public: FunctorFacade( HavingShapeFunctor* p ) : x(p) {} operator bool() const { return x->bound(); } FunctorValue operator*() const { return &*x->value(); } OperatorRightArrowProxy< FunctorValue > operator->() const { return FunctorValue( &*x->value() ); } void* name() const { //return dynamic_cast >*>( &*x )->name(); return dynamic_cast*>( &*x )->name(); } }; template std::ostream& operator<<( std::ostream& o, const FunctorFacade& ff ) { if( ff ) return o << F::name << "(" << ff->arg1() << "," << ff->arg2() << "," << ff->arg3() << ")"; else return o << "_" << ff.name(); } template std::ostream& operator<<( std::ostream& o, const FunctorFacade& ff ) { if( ff ) return o << F::name << "(" << ff->arg1() << "," << ff->arg2() << ")"; else return o << "_" << ff.name(); } template std::ostream& operator<<( std::ostream& o, const FunctorFacade& ff ) { if( ff ) return o << F::name << "(" << ff->arg1() << ")"; else return o << "_" << ff.name(); } ////////////////////////////////////////////////////////////////////// // FIX THIS (per .h file) IRef it_fail( new FailImpl ); IRef it_end_of_query( new EndOfQuery ); DontCare _; Rep::FailRep fail; Rep::SucceedRep succeed; } // end namespace impl ////////////////////////////////////////////////////////////////////// // Here are all the names just visible in the "lcpp" namespace. // types using impl::Empty; using impl::Environment; using impl::Functor; using impl::Rep::LogicVariable; using impl::QRT; using impl::AtomFacade; using impl::FunctorValue; using impl::FunctorFacade; // values using impl::_; using impl::fail; using impl::succeed; // functions (which would probably be found with Koenig lookup even if // we didn't export the names here) using impl::Rep::not_provable; using impl::lassert; using impl::query; using impl::iquery; using impl::lquery; // Note that stuff like the operator overloads in Rep are not explicitly // exported; those are the only other things that clients can use which // don't explicitly appear here, I think. } // end namespace lcpp