// // Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is granted without fee, // provided that the above copyright notice and this permission notice // appear in all source code copies and supporting documentation. The // software is provided "as is" without any express or implied // warranty. /* List of things I know I can do better... - being more careful about LEs and 'wrapped' LEs (LambdaExp), so that I don't end up unnecessarily wrapping getses, etc. Indeed, design so that comprehension commas make sense... - a way to ask for a fresh variable - have any LE which is sans-free-vars be a lambda--that is, callable via no-arg op(). this will make "compM[ yadda ]()" work, yay! - this looks like a bit of work, and will need new LETypes like COMPX or something, so I've decided not to do it syntax summary: lambda(X,Y)[ LE ] //(a,b) let[ X==f[a], Y==g[X,b] ].in[ LExy ] //() letrec[ x==f[x,y], y==g[x,y] ].in[ LExy ] //() compM()[ LE | LE, x<=LE, guard[LE] ] //() doM[ LE, x<=LE, LE ] //() if0,if1,if2 Everything centers around LEs; whether LEs have free vars can be key to whether they're callable; explicit lambdas are a special case of callable LEs where certain bindings on params happen. */ #ifndef FCPP_LAMBDA_DOT_H #define FCPP_LAMBDA_DOT_H #include "full.h" #ifdef FCPP_ENABLE_LAMBDA namespace fcpp { namespace fcpp_lambda { ////////////////////////////////////////////////////////////////////// // Literate error messages look nicer when emitted as compiler // diagnostics when they're not deeply nested inside classes, so we move // them all out to the 'top' level of this namespace here. ////////////////////////////////////////////////////////////////////// template struct TheActualTypeOfTheLambdaExpressionIsNotConvertibleToItsGivenType; template struct TheActualTypeOfTheLambdaExpressionIsNotConvertibleToItsGivenType { typedef int Error; }; template struct YouCannotInvokeALambdaContainingFreeVars {}; template struct TheTypeSpecYouHaveGivenIsIncompatibleWithItsLE; template struct TheTypeSpecYouHaveGivenIsIncompatibleWithItsLE { typedef int Error; }; template struct IfExpressionMustHaveTypeConvertibleToBool; template struct IfExpressionMustHaveTypeConvertibleToBool { typedef EE Type; }; template struct ActualTypeOfFalseBranchMustBeImplicitlyConvertibleToTypeOfTrueBranch; template struct ActualTypeOfFalseBranchMustBeImplicitlyConvertibleToTypeOfTrueBranch { typedef TT Error; }; template struct ActualTypeOfTrueBranchMustBeImplicitlyConvertibleToTypeOfFalseBranch; template struct ActualTypeOfTrueBranchMustBeImplicitlyConvertibleToTypeOfFalseBranch { typedef FF Error; }; template struct TrueAndFalseBranchOfIfMustHaveSameType; template struct TrueAndFalseBranchOfIfMustHaveSameType { typedef TT Type; }; template struct YouCannotPassTheSameLambdaVarTo_lambda_MoreThanOnce; template <> struct YouCannotPassTheSameLambdaVarTo_lambda_MoreThanOnce { static inline void go() {} }; ////////////////////////////////////////////////////////////////////// // Useful helpers ////////////////////////////////////////////////////////////////////// // some quick forward decls namespace exp { template class LambdaVar; template class Value; } using exp::LambdaVar; template struct ThunkifyType { struct Result { template struct Go { typedef T Type; }; }; }; ////////////////////////////////////////////////////////////////////// // Environment stuff ////////////////////////////////////////////////////////////////////// // I seem to recall that // ET - Environment Thunk // BE - Binding Environment // TE - Type Environment // Yes. See pre_lambda.h for a little more explanation. struct NIL_ET { template struct Go { typedef NIL TE; typedef NIL BE; }; }; template struct EraseLVsFromET { struct Result { template struct Go { typedef typename OldET::template Go::TE TE1; typedef typename OldET::template Go::BE BE1; struct BPred { template struct Go; template struct Go > { static const bool value = !(Contains >::value); }; }; typedef Filter BF; typedef typename BF::Result BE; static inline BE go( const BE1& x ) { return BF::go(x); } struct TPred { template struct Go; template struct Go > { static const bool value = !(Contains >::value); }; }; typedef Filter TF; typedef typename TF::Result TE; }; }; }; template struct ETUpdateX { struct Result { template struct Go { typedef CONS,NIL> BoundVars; typedef typename ET1::template Go::BE BE1; typedef typename EraseLVsFromET::Result ET2; typedef typename ET2::template Go::TE TE2; typedef typename ET2::template Go::BE BE2; typedef typename exp::Value LEX; typedef BEPair BEX; typedef CONS BE; typedef typename ThunkifyType::Result XTT; typedef TEPair TEX; typedef CONS TE; static inline BE go( const BE1& be, const X& x ) { return BE( BEX(LEX(x)), ET2::template Go::go(be) ); } }; }; }; template struct ETUpdateXY { struct Result { template struct Go { typedef CONS,CONS,NIL> > BoundVars; typedef typename ET1::template Go::BE BE1; typedef typename EraseLVsFromET::Result ET2; typedef typename ET2::template Go::TE TE2; typedef typename ET2::template Go::BE BE2; typedef typename exp::Value LEX; typedef BEPair BEX; typedef typename exp::Value LEY; typedef BEPair BEY; typedef CONS YBE; typedef CONS BE; typedef typename ThunkifyType::Result XTT; typedef TEPair TEX; typedef typename ThunkifyType::Result YTT; typedef TEPair TEY; typedef CONS > TE; static inline BE go( const BE1& be, const X& x, const Y& y ) { return BE( BEX(LEX(x)), YBE( BEY(LEY(y)), ET2::template Go::go(be) ) ); } }; }; }; template struct ETUpdateXYZ { struct Result { template struct Go { typedef CONS,CONS, CONS,NIL> > > BoundVars; typedef typename ET1::template Go::BE BE1; typedef typename EraseLVsFromET::Result ET2; typedef typename ET2::template Go::TE TE2; typedef typename ET2::template Go::BE BE2; typedef typename exp::Value LEX; typedef BEPair BEX; typedef typename exp::Value LEY; typedef BEPair BEY; typedef typename exp::Value LEZ; typedef BEPair BEZ; typedef CONS ZBE; typedef CONS YBE; typedef CONS BE; typedef typename ThunkifyType::Result XTT; typedef TEPair TEX; typedef typename ThunkifyType::Result YTT; typedef TEPair TEY; typedef typename ThunkifyType::Result ZTT; typedef TEPair TEZ; typedef CONS > > TE; static inline BE go( const BE1& be, const X& x, const Y& y, const Z& z ) { return BE( BEX(LEX(x)), YBE( BEY(LEY(y)), ZBE( BEZ(LEZ(z)), ET2::template Go::go(be) ) ) ); } }; }; }; ////////////////////////////////////////////////////////////////////// // The lambda expression types, all defined right together here // in one big batch ////////////////////////////////////////////////////////////////////// namespace exp { template class LambdaExp : public LEBase { X x; public: LambdaExp( const X& xx ) : x(xx) { EnsureLE::go(); } typedef typename X::FreeVars FreeVars; template struct MyType { typedef typename X::template MyType::TypeThunk TypeThunk; }; template struct RecheckType { typedef typename X::template RecheckType::Ok Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& be ) const { return x.template eval( be ); } typedef LambdaExp This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template class Value : public LEBase { T data; public: Value( const T& x ) : data(x) {} typedef NIL FreeVars; template struct MyType { struct TypeThunk { template struct Go { typedef T Type; }; }; }; template struct RecheckType { typedef int Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& ) const { return data; } typedef Value This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template class LambdaVar : public LEBase { // 'ii' is used to get around what appears to be a g++ bug... public: template struct Lookup; template struct Lookup,Rest> > { typedef typename T::template Go::Type Type; }; template struct Lookup > { typedef typename Lookup::Type Type; }; private: template struct Find; template struct Find,Rest>,WBE> { static inline R go( const CONS,Rest>& be, const WBE& wbe ) { return be.head.value.template eval(wbe); } }; template struct Find,WBE> { static inline R go( const CONS& be, const WBE& wbe ) { return Find::go( be.tail, wbe ); } }; public: typedef CONS FreeVars; template struct MyType { struct TypeThunk { template struct Go { typedef typename EnvThunk::template Go::TE TE; typedef typename Lookup::Type Type; }; }; }; template struct RecheckType { typedef int Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& be ) const { typedef typename MyType::TypeThunk::template Go::Type Result; typedef typename EnvThunk::template Go::BE BE; return Find::go(be,be); } typedef LambdaVar This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template class Call : public LEBase { Fun fun; Args args; public: template struct TypeHelper; template struct TypeHelper { typedef typename RT::ResultType Type; }; template struct TypeHelper > { typedef typename A1::template MyType::TypeThunk XTT; typedef typename XTT::template Go::Type X; typedef typename RT::ResultType Type; }; template struct TypeHelper > > { typedef typename A1::template MyType::TypeThunk XTT; typedef typename XTT::template Go::Type X; typedef typename A2::template MyType::TypeThunk YTT; typedef typename YTT::template Go::Type Y; typedef typename RT::ResultType Type; }; template struct TypeHelper > > > { typedef typename A1::template MyType::TypeThunk XTT; typedef typename XTT::template Go::Type X; typedef typename A2::template MyType::TypeThunk YTT; typedef typename YTT::template Go::Type Y; typedef typename A3::template MyType::TypeThunk ZTT; typedef typename ZTT::template Go::Type Z; typedef typename RT::ResultType Type; }; template struct CheckHelper; template struct CheckHelper { typedef int Result; }; template struct CheckHelper > { typedef typename AlwaysFirst::Ok, typename CheckHelper::Result>::Type Result; }; template struct EvalHelp; template struct EvalHelp { static inline R go( const Fun& f, const NIL&, const BE& be ) { return (f.template eval(be))(); } }; template struct EvalHelp > { static inline R go( const Fun& f, const CONS& a, const BE& be ) { return (f.template eval(be))(a.head.template eval(be)); } }; template struct EvalHelp > > { static inline R go( const Fun& f, const CONS >& a, const BE& be ) { return (f.template eval(be))( a.tail.head.template eval(be), a.head.template eval(be)); } }; template struct EvalHelp > > > { static inline R go( const Fun& f, const CONS > >& a, const BE& be ) { return (f.template eval(be))( a.tail.tail.head.template eval(be), a.tail.head.template eval(be), a.head.template eval(be)); } }; struct FoldrOp { template struct Go { typedef typename AppendList::Result Result; }; }; typedef typename Foldr >::Result AccumulatedFreeVars; Call( const Fun& f, const Args& a ) : fun(f), args(a) { EnsureLE::go(); EnsureLEList::go(); } typedef typename RemoveDuplicates::Result FreeVars; template struct MyType { struct TypeThunk { template struct Go { typedef typename Fun::template MyType::TypeThunk FTT; typedef typename FTT::template Go::Type F; typedef typename TypeHelper::Type Type; }; }; }; template struct RecheckType { typedef typename CheckHelper >::Result Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename ET::template Go::BE& be ) const { typedef typename ET::template Go::BE BE; typedef typename MyType::TypeThunk::template Go::Type Result; return EvalHelp::go(fun,args,be); } typedef Call This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; // This is a weird special class only BindingEnvExp below uses... template class AddEnvLE : public LEBase { LE exp; BE1 be1; B b; public: AddEnvLE( const LE& e, const BE1& x, const B& y ) : exp(e), be1(x), b(y) {} typedef FV FreeVars; template struct MyType { struct TypeThunk { template struct Go { typedef typename LE::template MyType::TypeThunk LETT; typedef typename LETT::template Go::Type Type; }; }; }; template struct RecheckType { typedef typename LE::template RecheckType::Ok Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& ) const { return exp.template eval( RealET::template Go::go(be1,b) ); } typedef AddEnvLE This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template class BindingEnvExp : public LEBase { // letrec semantics B binders; LE exp; template struct AccumFree; template struct AccumFree { typedef NIL Result; }; template struct AccumFree,Rest> > { typedef typename AppendList::Result>::Result Result; }; template struct AccumBound; template struct AccumBound { typedef NIL Result; }; template struct AccumBound,Rest> > { typedef CONS,typename AccumBound::Result> Result; }; public: typedef typename AccumBound::Result NewlyBoundVars; typedef typename AccumFree::Result FreeVarsInBinders; // In order to compute the environment for "exp", we must follow // these steps: // - Call the outer env E1 // - foreach lv in lhs of binders, erase lv-entries from E1 => E2 // - foreach binder in binders, add (binder.rhs)> // BE/TE pair to E2 => E3 // Now exp should be evaled in E3. template struct UnusualTTHelper { template struct Go { typedef typename Inner::template MyType::TypeThunk ITT; typedef typename ITT::template Go::Type Type; }; }; // Note the trick; we take the very result we are computing (ET3) as // a template parameter! Ha ha! Darn I'm clever. :) template struct Env3FromEnv2; template struct Env3FromEnv2 { struct Result { template struct Go { typedef typename ET2::template Go::TE TE; typedef typename ET2::template Go::BE BE; static inline BE go( const BE& x, const NIL&, const BE1&, const BB& ) { return x; } }; }; }; template struct Env3FromEnv2,Rest>,NBV,BE1,BB> { struct Result { template struct Go { typedef typename ET2::template Go::BE BE2; typedef typename Env3FromEnv2::Result Recurse; typedef typename ListDifference::Result LEFV; // Inner will capture the letrec environment (by value) typedef AddEnvLE Inner; typedef BEPair BEP; typedef CONS::BE> BE; static inline BE go( const BE2& be, const CONS,Rest>& binders, const BE1& be1, const BB& b ) { return BE( BEP(Inner(binders.head.exp,be1,b)), Recurse::template Go::go(be,binders.tail,be1,b) ); } typedef UnusualTTHelper TT; typedef TEPair TEP; typedef CONS::TE> TE; }; }; }; template struct MakeNewET { struct Result { template struct Go { typedef typename OrigET::template Go::BE BE1; typedef typename EraseLVsFromET::Result E2; // Here is the trick to tie the recursive knot: typedef typename Env3FromEnv2::Result E3; typedef typename OrigET::template Go::BE BE1; typedef typename E3::template Go::BE BE; typedef typename E3::template Go::TE TE; static inline BE go( const BE1& be, const B& binders ) { return E3::template Go::go( E2::template Go::go(be), binders, be, binders ); } }; }; }; private: template struct CheckHelp; template struct CheckHelp { typedef int Result; }; template struct CheckHelp,Rest> > { typedef typename LEa::template RecheckType::Ok ThisOne; typedef typename AlwaysFirst::Result>::Type Result; }; public: BindingEnvExp( const B& g, const LE& e ) : binders(g), exp(e) { EnsureBinderList::go(); EnsureLE::go(); } typedef typename RemoveDuplicates::Result, NewlyBoundVars>::Result>::Result FreeVars; template struct MyType { typedef typename LE::template MyType::Result>::TypeThunk TypeThunk; }; template struct RecheckType { typedef typename MakeNewET::Result NET; typedef typename AlwaysFirst< typename LE::template RecheckType::Ok, typename CheckHelp::Result>::Type Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& be ) const { typedef typename MakeNewET::Result NET; return exp.template eval( NET::template Go::go(be,binders) ); } typedef BindingEnvExp This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template // To-Be-Bound Vars, in correct order class LambdaExpWithFreeVars : public LEBase { // This class's name isn't great; nearly every kind of lambda // expression has free variables. Specifically, this class is about // such LEs which are created like so: // lambda(X)[ f[X,Y] ] // LEs which, when evaluated, will result in a functoid which // captures a particular outer binding environment. LE exp; public: template class Lambda0WithFreeVars : public CFunType::TypeThunk::template Go::Type> { typedef typename ET::template Go::BE BE; LEa exp; BE env; public: Lambda0WithFreeVars( const LEa& e, const BE& be ) : exp(e), env(be) {} typename AlwaysFirst::TypeThunk ::template Go::Type, typename LEa::template RecheckType::Ok>::Type operator()() const { return exp.template eval( env ); } }; template class Lambda1WithFreeVars { typedef typename ET::template Go::BE BE; LEa exp; BE env; template struct NewET { typedef typename ETUpdateX::Result Result; }; public: Lambda1WithFreeVars( const LEa& e, const BE& be ) : exp(e), env(be) {} template struct Sig : public FunType::Result> ::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x ) const { return exp.template eval::Result> ( NewET::Result::template Go::go( env, x ) ); } }; template class Lambda2WithFreeVars { typedef typename ET::template Go::BE BE; LEa exp; BE env; template struct NewET { typedef typename ETUpdateXY::Result Result; }; public: Lambda2WithFreeVars( const LEa& e, const BE& be ) : exp(e), env(be) {} template struct Sig : public FunType::Result> ::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return exp.template eval::Result> ( NewET::Result::template Go::go( env, x, y ) ); } }; template class Lambda3WithFreeVars { typedef typename ET::template Go::BE BE; LEa exp; BE env; template struct NewET { typedef typename ETUpdateXYZ::Result Result; }; public: Lambda3WithFreeVars( const LEa& e, const BE& be ) : exp(e), env(be) {} template struct Sig : public FunType::Result> ::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { return exp.template eval::Result> ( NewET::Result::template Go::go( env, x, y, z ) ); } }; template struct NumBoundVarsHelp; template struct NumBoundVarsHelp { typedef Lambda0WithFreeVars Lam; typedef Full0 Full; }; template struct NumBoundVarsHelp,NIL> > { typedef Lambda1WithFreeVars Lam; typedef Full1 Full; }; template struct NumBoundVarsHelp,CONS, NIL> > > { typedef Lambda2WithFreeVars Lam; typedef Full2 Full; }; template struct NumBoundVarsHelp,CONS, CONS,NIL> > > > { typedef Lambda3WithFreeVars Lam; typedef Full3 Full; }; LambdaExpWithFreeVars( const LE& e ) : exp(e) { EnsureLE::go(); } typedef typename RemoveDuplicates::Result>::Result FreeVars; template struct MyType { typedef typename NumBoundVarsHelp::Full Full; typedef typename ThunkifyType::Result TypeThunk; }; template struct RecheckType { typedef typename LE::template RecheckType::Ok Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename EnvThunk::template Go::BE& be ) const { typedef NumBoundVarsHelp NBVH; typedef typename NBVH::Lam Lam; typedef typename NBVH::Full Full; return Full( Lam(exp,be) ); } YouCannotInvokeALambdaContainingFreeVars operator()() const { return 0; } template YouCannotInvokeALambdaContainingFreeVars operator()(const X&) const { return 0; } template YouCannotInvokeALambdaContainingFreeVars operator()(const X&, const Y&) const { return 0; } template YouCannotInvokeALambdaContainingFreeVars operator()(const X&, const Y&, const Z&) const { return 0; } template struct Sig { typedef typename YouCannotInvokeALambdaContainingFreeVars ::AndThusYouShouldNotBeTryingToUseItsSigEither Arg1Type; typedef typename YouCannotInvokeALambdaContainingFreeVars ::AndThusYouShouldNotBeTryingToUseItsSigEither Arg2Type; typedef typename YouCannotInvokeALambdaContainingFreeVars ::AndThusYouShouldNotBeTryingToUseItsSigEither Arg3Type; typedef typename YouCannotInvokeALambdaContainingFreeVars ::AndThusYouShouldNotBeTryingToUseItsSigEither ResultType; }; typedef LambdaExpWithFreeVars This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; template class IfLE : public LEBase { E e; T t; F f; public: template struct XType; template struct XRecheckType; // Normal if type deduction template struct XType { typedef typename T::template MyType::TypeThunk TypeThunk; }; template struct XRecheckType { typedef typename E::template MyType::TypeThunk ETT; typedef typename T::template MyType::TypeThunk TTT; typedef typename F::template MyType::TypeThunk FTT; typedef typename ETT::template Go::Type EType; typedef typename TTT::template Go::Type TType; typedef typename FTT::template Go::Type FType; static const bool b = ImplicitlyConvertible::value; typedef typename AlwaysFirst::Type, typename IfExpressionMustHaveTypeConvertibleToBool::Type>::Type, typename E::template RecheckType::Ok>::Type, typename T::template RecheckType::Ok>::Type, typename F::template RecheckType::Ok>::Type Ok; }; // Type deduction based on true-branch template struct XType { typedef typename T::template MyType::TypeThunk TypeThunk; }; template struct XRecheckType { typedef typename E::template MyType::TypeThunk ETT; typedef typename T::template MyType::TypeThunk TTT; typedef typename F::template MyType::TypeThunk FTT; typedef typename ETT::template Go::Type EType; typedef typename TTT::template Go::Type TType; typedef typename FTT::template Go::Type FType; static const bool bx = ImplicitlyConvertible::value; typedef typename IfExpressionMustHaveTypeConvertibleToBool::Type Foo; static const bool b = ImplicitlyConvertible::value; typedef typename ActualTypeOfFalseBranchMustBeImplicitlyConvertibleToTypeOfTrueBranch ::Error Tmp; typedef typename AlwaysFirst::Type, typename E::template RecheckType::Ok>::Type, typename T::template RecheckType::Ok>::Type, typename F::template RecheckType::Ok>::Type Ok; }; // Type deduction based on false-branch template struct XType { typedef typename F::template MyType::TypeThunk TypeThunk; }; template struct XRecheckType { typedef typename E::template MyType::TypeThunk ETT; typedef typename T::template MyType::TypeThunk TTT; typedef typename F::template MyType::TypeThunk FTT; typedef typename ETT::template Go::Type EType; typedef typename TTT::template Go::Type TType; typedef typename FTT::template Go::Type FType; static const bool bx = ImplicitlyConvertible::value; typedef typename IfExpressionMustHaveTypeConvertibleToBool::Type Foo; static const bool b = ImplicitlyConvertible::value; typedef typename ActualTypeOfTrueBranchMustBeImplicitlyConvertibleToTypeOfFalseBranch ::Error Tmp; typedef typename AlwaysFirst::Type, typename E::template RecheckType::Ok>::Type, typename T::template RecheckType::Ok>::Type, typename F::template RecheckType::Ok>::Type Ok; }; IfLE( const E& ee, const T& tt, const F& ff ) : e(ee), t(tt), f(ff) { EnsureLE::go(); EnsureLE::go(); EnsureLE::go(); } typedef typename RemoveDuplicates::Result >::Result>::Result FreeVars; template struct MyType { typedef typename XType::TypeThunk TypeThunk; }; template struct RecheckType { typedef typename XRecheckType::Ok Ok; }; template typename MyType::TypeThunk::template Go::Type eval( const typename ET::template Go::BE& be ) const { if( e.template eval(be) ) return t.template eval(be); else return f.template eval(be); } typedef IfLE This; template typename BracketCallable::Result operator[]( const A& a ) const { return BracketCallable::go( *this, a ); } }; // operator, overloads // // Koenig lookup will only find these overloads if one of the arguments // to comma is an LE (a type defined in this namespace). // Either the LHS is already a CONS... template CONS::Type,CONS > operator,( const CONS& lhs, const RHS& rhs ) { return CONS::Type,CONS > ( LEify::go(rhs), lhs ); } // ... or it's not template CONS::Type,typename LEListify::Type> operator,( const LHS& lhs, const RHS& rhs ) { return CONS::Type,typename LEListify::Type> ( LEify::go(rhs), LEListify::go(lhs) ); } } // end namespace exp ////////////////////////////////////////////////////////////////////// // lambda() and the functoids that get made when all the vars are bound // and we make it back out into "C++ space" ////////////////////////////////////////////////////////////////////// template class Lambda0 : public CFunType::TypeThunk::template Go::Type> { LE exp; public: Lambda0( const LE& e ) : exp(e) { EnsureLE::go(); } typename LE::template MyType::TypeThunk::template Go::Type operator()() const { return exp.template eval( NIL() ); } }; template class Lambda1 { LE exp; template struct NewET { typedef typename ETUpdateX::Result Result; }; public: Lambda1( const LE& e ) : exp(e) { EnsureLE::go(); } template struct Sig : public FunType::Result>::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x ) const { typedef typename NewET::Result NET; return exp.template eval( NET::template Go::go(NIL(),x) ); } }; template class Lambda2 { LE exp; template struct NewET { typedef typename ETUpdateXY::Result Result; }; public: Lambda2( const LE& e ) : exp(e) { EnsureLE::go(); } template struct Sig : public FunType::Result> ::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { typedef typename NewET::Result NET; return exp.template eval( NET::template Go::go(NIL(),x,y) ); } }; template class Lambda3 { LE exp; template struct NewET { typedef typename ETUpdateXYZ::Result Result; }; public: Lambda3( const LE& e ) : exp(e) { EnsureLE::go(); } template struct Sig : public FunType::Result> ::TypeThunk::template Go::Type> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { typedef typename NewET::Result NET; return exp.template eval( NET::template Go::go(NIL(),x,y,z) ); } }; // LambdaThingy is the temporary object that lambda() returns which // understands operator[] calls. template struct LambdaThingy { typedef TBBV VarsThisLambdaBinds; template struct Help2 { typedef exp::LambdaExpWithFreeVars Result; typedef Result Full; }; template struct Help2 { typedef Lambda0 Result; typedef Full0 Full; }; template struct Help2,NIL> > { typedef Lambda1 Result; typedef Full1 Full; }; template struct Help2,CONS,NIL> > > { typedef Lambda2 Result; typedef Full2 Full; }; template struct Help2,CONS, CONS,NIL> > > > { typedef Lambda3 Result; typedef Full3 Full; }; template struct Helper { typedef typename ListDifference::Result FreeVars; typedef typename Help2::Result Result; typedef typename Help2::Full Full; }; public: template struct RT { typedef typename Helper::Type>::Full Type; }; template typename RT::Type operator[]( const E& e ) const { typedef typename Helper::Type>::Result Result; typedef typename Helper::Type>::Full Full; return Full( Result( LEify::go(e) ) ); } }; inline LambdaThingy lambda() { return LambdaThingy(); } template LambdaThingy,NIL> > lambda( const LambdaVar& ) { return LambdaThingy,NIL> >(); } template LambdaThingy,CONS,NIL> > > lambda( const LambdaVar&, const LambdaVar& ) { YouCannotPassTheSameLambdaVarTo_lambda_MoreThanOnce<(i==j)>::go(); return LambdaThingy,CONS,NIL> > >(); } template LambdaThingy,CONS,CONS,NIL> > > > lambda( const LambdaVar&, const LambdaVar&, const LambdaVar& ) { YouCannotPassTheSameLambdaVarTo_lambda_MoreThanOnce< (i==j || i==k || j==k) >::go(); return LambdaThingy,CONS, CONS,NIL> > > >(); } ////////////////////////////////////////////////////////////////////// // lambda language constructs ////////////////////////////////////////////////////////////////////// template struct IfLambdaoid { template exp::IfLE operator[]( const CONS > >& x ) const { EnsureLE::go(); EnsureLE::go(); EnsureLE::go(); return exp::IfLE( x.tail.tail.head, x.tail.head, x.head ); } }; template Binder::Type> operator==( exp::LambdaVar, const E& e ) { return Binder::Type>( LEify::go(e) ); } template CONS,typename BinderListify::Type> operator,( const LHS& lhs, const Binder& b ) { return CONS,typename BinderListify::Type> ( b, BinderListify::go(lhs) ); } template CONS,CONS > operator,( const CONS& lhs, const Binder& b ) { return CONS,CONS >( b, lhs ); } ////////////////////////////////////////////////////////////////////// // LEType stuff ////////////////////////////////////////////////////////////////////// template struct CALL; template struct LV; template struct IF0; template struct IF1; template struct IF2; template struct LAM; template struct LEType { typedef T Type; }; template struct LET_LEListify { typedef typename LEify::Type>::Type LE_D; typedef CONS::Type> Type; }; template struct LET_LEListify { typedef typename LEify::Type>::Type LE_C; typedef CONS::Type> Type; }; template struct LET_LEListify { typedef typename LEify::Type>::Type LE_B; typedef CONS::Type> Type; }; template struct LET_LEListify { typedef typename LEListify::Type>::Type Type; }; template struct LEType< CALL > { typedef typename LEify::Type>::Type FF; typedef exp::Call::Type> Type; }; template struct LEType< CALL > { typedef typename LEify::Type>::Type FF; typedef exp::Call::Type> Type; }; template struct LEType< CALL > { typedef typename LEify::Type>::Type FF; typedef exp::Call::Type> Type; }; template struct LEType< CALL > { typedef typename LEify::Type>::Type FF; typedef exp::Call Type; }; template struct LEType< LV > { typedef LambdaVar Type; }; template struct LEType< IF0 > { typedef typename LEify::Type>::Type EE; typedef typename LEify::Type>::Type TT; typedef typename LEify::Type>::Type FF; typedef exp::IfLE Type; }; template struct LEType< IF1 > { typedef typename LEify::Type>::Type EE; typedef typename LEify::Type>::Type TT; typedef typename LEify::Type>::Type FF; typedef exp::IfLE Type; }; template struct LEType< IF2 > { typedef typename LEify::Type>::Type EE; typedef typename LEify::Type>::Type TT; typedef typename LEify::Type>::Type FF; typedef exp::IfLE Type; }; template struct LEType< LAM,LV,LV,E> > { typedef typename LEType::Type EE; typedef typename LambdaThingy,CONS, CONS,NIL> > > >::template RT::Type Type; }; template struct LEType< LAM,LV,E,Void> > { typedef typename LEType::Type EE; typedef typename LambdaThingy,CONS, NIL> > >::template RT::Type Type; }; template struct LEType< LAM,E,Void,Void> > { typedef typename LEType::Type EE; typedef typename LambdaThingy, NIL> >::template RT::Type Type; }; template struct LEType< LAM > { typedef typename LEType::Type EE; typedef typename LambdaThingy::template RT::Type Type; }; ////////////////////////////////////////////////////////////////////// // more lambda language constructs ////////////////////////////////////////////////////////////////////// struct LetLambdaoid { template struct InLambdaoid { class Help { BL bl; public: template struct Lambdify; template struct Lambdify,NIL>,LE> { typedef typename LEType,LE>,LEa> >::Type R; static inline R go( const CONS,NIL>& binders, const LE& le ) { LambdaVar X; return lambda(X)[ le ][ binders.head.exp ]; } }; template struct Lambdify,Rest>,LE> { typedef typename LEType,LE>,LEa> >::Type Inner; typedef typename Lambdify::R R; static inline R go( const CONS,Rest>& binders, const LE& le ) { LambdaVar X; return Lambdify::go( binders.tail, lambda(X)[ le ][ binders.head.exp ] ); } }; Help( const BL& l ) : bl(l) {} template struct RT { typedef typename Lambdify::Type>::R Type; }; template typename RT::Type operator[]( const E& e ) { return Lambdify::Type>::go ( bl, LEify::go(e) ); } }; Help in; InLambdaoid( const BL& l ) : in(l) {} }; template struct RT { typedef InLambdaoid::Type> Type; }; template typename RT::Type operator[]( const BL& bl ) const { EnsureBinderList::Type>::go(); return InLambdaoid::Type> ( BinderListify::go(bl) ); } }; struct LetRecLambdaoid { template struct InLambdaoid { class Help { BL bl; public: Help( const BL& l ) : bl(l) {} template struct RT { typedef exp::BindingEnvExp::Type> Type; }; template typename RT::Type operator[]( const E& e ) { return exp::BindingEnvExp::Type> ( bl, LEify::go(e) ); } }; Help in; InLambdaoid( const BL& l ) : in(l) {} }; template struct RT; template friend struct RT; template struct RT { typedef InLambdaoid::Type> Type; }; template typename RT::Type operator[]( const BL& bl ) const { EnsureBinderList::Type>::go(); return InLambdaoid::Type> ( BinderListify::go(bl) ); } }; ////////////////////////////////////////////////////////////////////// // more LEType stuff ////////////////////////////////////////////////////////////////////// template struct BIND; template struct LET; template struct LETREC; template struct LET_BinderListify { typedef CONS::Type> Type; }; template struct LET_BinderListify { typedef CONS::Type> Type; }; template struct LET_BinderListify { typedef CONS::Type> Type; }; template struct LET_BinderListify { typedef typename BinderListify::Type Type; }; template struct LEType< LET,LE,Void,Void> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef typename LetLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; template struct LEType< LET,BIND,LE,Void> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef Binder::Type>::Type> BB; typedef typename LetLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; template struct LEType< LET,BIND,BIND,LE> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef Binder::Type>::Type> BB; typedef Binder::Type>::Type> CC; typedef typename LetLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; template struct LEType< LETREC,LE,Void,Void> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef typename LetRecLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; template struct LEType< LETREC,BIND,LE,Void> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef Binder::Type>::Type> BB; typedef typename LetRecLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; template struct LEType< LETREC,BIND,BIND,LE> > { typedef typename LEType::Type LELE; typedef Binder::Type>::Type> AA; typedef Binder::Type>::Type> BB; typedef Binder::Type>::Type> CC; typedef typename LetRecLambdaoid::template RT::Type>::Type::Help::template RT::Type Type; }; } // end namespace fcpp_lambda FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN fcpp_lambda::IfLambdaoid if0; FCPP_MAYBE_EXTERN fcpp_lambda::IfLambdaoid if1; FCPP_MAYBE_EXTERN fcpp_lambda::IfLambdaoid if2; FCPP_MAYBE_EXTERN fcpp_lambda::LetRecLambdaoid letrec; FCPP_MAYBE_EXTERN fcpp_lambda::LetLambdaoid let; FCPP_MAYBE_NAMESPACE_CLOSE using fcpp_lambda::LambdaVar; using fcpp_lambda::lambda; // all that work for _one_ exported function :) using fcpp_lambda::LEType; using fcpp_lambda::CALL; using fcpp_lambda::LV; using fcpp_lambda::IF0; using fcpp_lambda::IF1; using fcpp_lambda::IF2; using fcpp_lambda::LAM; using fcpp_lambda::BIND; using fcpp_lambda::LET; using fcpp_lambda::LETREC; } // end namespace fcpp #endif #endif