// // 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. #ifndef FCPP_MONAD_DOT_H #define FCPP_MONAD_DOT_H namespace fcpp { template struct ThisTypeIsNotAnInstanceOfAnInferrableMonad {}; template struct MonadError { inline static void error() {} }; template struct MonadError > {}; template struct MonadTraitsSpecializer { typedef ThisTypeIsNotAnInstanceOfAnInferrableMonad Monad; }; template struct MonadTraits { typedef typename MonadTraitsSpecializer::Monad Monad; inline static void ensure_is_instance_of_monad() { MonadError::error(); } }; ////////////////////////////////////////////////////////////////////// // If a monad has a type constructor which is not a type synonym, then // we call it an "inferrable monad". // For any monad M, you can conjure up one of its functoids via, e.g. // unitM() bindM() // whereas for an inferrable monad, you can just refer to e.g. // bind // which will use the MonadTraitsSpecializer to infer "M" from "M a". // // (Section 4.3.2 in the Haskell Report explains that an instance of a // type class's type constructor cannot be a type synonym.) namespace impl { template struct XUnitM { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const A& a ) const { return Monad::unit(a); } }; } template Full1 > unitM() { return makeFull1( impl::XUnitM() ); } template struct UnitM { typedef Full1 > Type; }; namespace impl { template struct XBindM { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { return Monad::bind(m,k); } }; } template Full2 > bindM() { return makeFull2( impl::XBindM() ); } template struct BindM { typedef Full2 > Type; }; namespace impl { template struct XBindM_ { template struct Sig : public FunType ::ResultType>::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { return Monad::bind( m, ignore(const_(k)) ); } }; } template Full2 > bindM_() { return makeFull2( impl::XBindM_() ); } template struct BindM_ { typedef Full2 > Type; }; template typename Monad::Zero zeroM() { return Monad::zero; } template struct ZeroM { typedef typename Monad::Zero Type; }; namespace impl { template struct XPlusM { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const MA& x, const MA2& y ) const { return Monad::plus(x,y); } }; } template Full2 > plusM() { return makeFull2( impl::XPlusM() ); } template struct PlusM { typedef Full2 > Type; }; namespace impl { template struct BindError {}; template <> struct BindError { static inline void error() {} }; template struct BindHelper { typedef typename MonadTraits::Monad MonadA; typedef typename MonadA::template UnRep::Type A; typedef typename MonadA::Bind::template Sig::ResultType ResultType; typedef typename MonadTraits::Monad MonadB; inline static void ensure_m_and_k_are_in_the_same_monad_instance() { BindError::sameType>::error(); } }; struct XBind { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { BindHelper::ensure_m_and_k_are_in_the_same_monad_instance(); typedef typename BindHelper::MonadA MM; return MM::bind(m,k); } }; } typedef Full2 Bind; FCPP_MAYBE_EXTERN Bind bind; namespace impl { struct XBind_ { template struct Sig : public FunType ::ResultType>::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { return bind( m, ignore(const_(k)) ); } }; } typedef Full2 Bind_; FCPP_MAYBE_EXTERN Bind_ bind_; namespace impl { template struct XMapM { template struct Sig : FunType::Type,M,typename LEType< LAM,CALL::Type, CALL > > > >::Type>::ResultType> {}; template typename Sig::ResultType operator()( const F& f, const M& m ) const { LambdaVar<1> A; return bindM()( m, lambda(A)[ unitM()[f[A]] ] ); } }; } template Full2 > mapM() { return makeFull2( impl::XMapM() ); } template struct MapM { typedef Full2 > Type; }; // If you can't beat 'em, JoinM! :) :) :) namespace impl { template struct XJoinM { template struct Sig : public FunType::Type,Z,Id>::ResultType> {}; template typename Sig::ResultType operator()( const Z& z ) const { return bindM()( z, id ); } }; } template Full1 > joinM() { return makeFull1( impl::XJoinM() ); } template struct JoinM { typedef Full1 > Type; }; ////////////////////////////////////////////////////////////////////// namespace fcpp_lambda { // Gets is not really an LE, but making it appear so makes op,() and // LEify work properly automagically. So we fake it to make the // implementation easier. namespace exp { template struct Gets : public LEBase { static const int my_lv = i; LE exp; Gets( const LE& e ) : exp(e) { EnsureLE::go(); }; }; } template exp::Gets::Type> operator<=( const LambdaVar&, const E& e ) { return exp::Gets::Type>( LEify::go(e) ); } ////////////////////////////////////////////////////////////////////// // Next on the agenda... // doM[ LE ] ==> LE // doM[ LE, stmts ] ==> bind_[ LE, doM[stmts] ] // doM[ X<=LE, stmts ] ==> bind[ LE, lambda(X)[ doM[stmts] ] ] // "doM" is an unfortunate name, as everything else monad-ly I've // written uses the 'M' suffix to say "I'm a template, pass me a monad // as a parameter, please", whereas this isn't true here. But I still // like "doM" better than "do_", and just "do" is a C++ keyword. struct DoM_Lambdaoid { template struct Helper2; template struct Helper2 { typedef FinalLE Result; static inline Result go( const FinalLE& le, const NIL& ) { return le; } }; template struct Helper2 > { typedef typename LEType >::Type Inner; typedef typename Helper2::Result Result; static inline Result go( const FinalLE& le, const CONS& rest ) { return Helper2::go( bind_[ rest.head, le ], rest.tail ); } }; template struct Helper2,Rest> > { typedef typename LEType,FinalLE> > >::Type Inner; typedef typename Helper2::Result Result; static inline Result go( const FinalLE& le, const CONS,Rest>& rest ) { LambdaVar X; return Helper2::go( bind[ rest.head.exp, lambda(X)[ le ] ], rest.tail ); } }; template struct Helper; template struct Helper > { typedef typename Helper2::Result Result; static inline Result go( const CONS& l ) { return Helper2::go( l.head, l.tail ); } }; template struct RT { typedef typename DoM_Lambdaoid::Helper::Type>::Result Type; }; template typename RT::Type operator[]( const X& x ) const { typedef typename LEListify::Type XP; return Helper::go( LEListify::go(x) ); } }; template struct DOM; template struct GETS; template struct LEType< GETS > { typedef exp::Gets::Type>::Type> Type; }; template struct LEType< DOM > { typedef typename LET_LEListify::Type L; typedef typename DoM_Lambdaoid::template RT::Type Type; }; template struct LEType< DOM > { typedef typename LET_LEListify::Type L; typedef typename DoM_Lambdaoid::template RT::Type Type; }; template struct LEType< DOM > { typedef typename LET_LEListify::Type L; typedef typename DoM_Lambdaoid::template RT::Type Type; }; template struct LEType< DOM > { typedef typename LET_LEListify::Type L; typedef typename DoM_Lambdaoid::template RT::Type Type; }; ////////////////////////////////////////////////////////////////////// // Finally, the mother-of-all-syntactic-sugar: comprehensions! // compM()[ LE ] // ==> unit()[ LE ] // compM()[ LE | LEa, stmts ] // ==> bindM_[ LEa, comp()[LE|stmts] ] // compM()[ LE | X<=LEa, stmts ] // ==> bindM[ LEa, lambda(X)[ comp()[LE|stmts] ] ] // compM()[ LE | guard[LEa], stmts ] // ==> if1[ LEa, comp()[LE|stmts], zero() ] // The vert (|) will be a bit of a pain, as it binds tighter than the // comma (but thankfully less tightly that <=), and so I'm gonna have to // make it return a VertPair or something as a new "exp" type which // operator,() can LEListify, and then have compM unwrap it on the back // end. Hmm, and just to ensure that we don't accidentally call C++'s // built-in operator|(), I think I'll outlaw the first form of compM // above, and require that there always be a vert and a right-hand-side // in user calls. Yup. namespace exp { template struct VertPair : public LEBase { LHS lhs; RHS rhs; VertPair( const LHS& l, const RHS& r ) : lhs(l), rhs(r) { EnsureLE::go(); EnsureLE::go(); } }; template VertPair::Type,typename LEify::Type> operator|( const LHS& l, const RHS& r ) { return VertPair::Type,typename LEify::Type> ( LEify::go(l), LEify::go(r) ); } template struct Guard : public LEBase { BFLE fun; Guard(const BFLE&f) : fun(f) { EnsureLE::go(); } }; } struct Guard_Lambdaoid { template exp::Guard::Type> operator[]( const BF& f ) const { return exp::Guard::Type>( LEify::go(f) ); } }; template struct compM { // Dig walks all the way down the list and gets to the LHS of the // VertPair at the end, and returns a _reference_ to it. This is // especially happy because it should translate to a no-op. template struct Dig; template struct Dig,NIL> > { typedef const LHS& Result; typedef LHS Type; static inline Result go( const CONS,NIL>& l ) { return l.head.lhs; } }; template struct Dig > { typedef typename Dig::Result Result; typedef typename Dig::Type Type; static inline Result go( const CONS& l ) { return Dig::go( l.tail ); } }; template struct Help2; template struct Help2 { typedef FinalLE Result; static inline Result go( const FinalLE& le, const NIL& ) { return le; } }; template struct Help2,NIL> > { typedef typename Help2 >::Result Result; static inline Result go( const FinalLE& le, const CONS,NIL>& x ) { return Help2 >::go ( le, CONS(x.head.rhs) ); } }; template struct Help2 > { typedef typename LEType::Type,LE, FinalLE> >::Type NextLE; typedef typename Help2::Result Result; static inline Result go( const FinalLE& le, const CONS& x ) { return Help2::go( bindM_()[ x.head, le ], x.tail ); } }; template struct Help2,Rest> > { typedef typename LEType::Type,LE, LAM,FinalLE> > >::Type NextLE; typedef typename Help2::Result Result; static inline Result go( const FinalLE& le, const CONS,Rest>& x ) { LambdaVar X; return Help2::go( bindM()[ x.head.exp, lambda(X)[ le ] ], x.tail ); } }; template struct Help2,Rest> > { typedef typename LEType::Type> >::Type NextLE; typedef typename Help2::Result Result; static inline Result go( const FinalLE& le, const CONS,Rest>& x ) { return Help2::go( if1[ x.head.fun, le, zeroM() ], x.tail ); } }; template struct Helper { typedef typename Dig::Type DigLE; typedef typename LEType::Type, DigLE> >::Type FinalLE; typedef typename Help2::Result Result; static inline Result go( const L& l ) { return Help2::go( unitM()[Dig::go(l)], l ); } }; template struct RT { typedef typename LEListify::Type XP; typedef typename Helper::Result Type; }; template typename RT::Type operator[]( const X& x ) const { return Helper::XP>::go( LEListify::go(x) ); } }; template struct GUARD; template struct LEType< GUARD > { typedef exp::Guard< typename LEify::Type>::Type > Type; }; template struct COMP {}; template struct LEType< COMP > { typedef typename LEify::Type>::Type LHST; typedef typename LEify::Type>::Type AT; typedef exp::VertPair T; typedef typename LET_LEListify::Type TE; typedef typename compM::template RT::Type Type; }; template struct LEType< COMP > { typedef typename LEify::Type>::Type LHST; typedef typename LEify::Type>::Type AT; typedef exp::VertPair T; typedef typename LET_LEListify::Type TE; typedef typename compM::template RT::Type Type; }; template struct LEType< COMP > { typedef typename LEify::Type>::Type LHST; typedef typename LEify::Type>::Type AT; typedef exp::VertPair T; typedef typename LET_LEListify::Type TE; typedef typename compM::template RT::Type Type; }; template struct LEType< COMP > { typedef typename LEify::Type>::Type LHST; typedef typename LEify::Type>::Type AT; typedef exp::VertPair T; typedef typename LET_LEListify::Type TE; typedef typename compM::template RT::Type Type; }; } // end namespace fcpp_lambda using fcpp_lambda::DOM; using fcpp_lambda::GETS; using fcpp_lambda::GUARD; using fcpp_lambda::COMP; using fcpp_lambda::compM; // a template type name FCPP_MAYBE_EXTERN fcpp_lambda::DoM_Lambdaoid doM; FCPP_MAYBE_EXTERN fcpp_lambda::Guard_Lambdaoid guard; ////////////////////////////////////////////////////////////////////// // Monad concepts ////////////////////////////////////////////////////////////////////// // Here we outline the C++ concepts necessary for monads to work in the // framework. /* concept Monad { // unit :: a -> m a // bind :: m a -> ( a -> m b ) -> m b typedef Unit; // a full functoid type static Unit unit; typedef Bind; // a full functoid type static Bind bind; } ////////////////////////////// // Inferrable Monads let you use bind() instead of bindM()(), and // are also the only Monads that work with do-notation (doM). concept InferrableMonad models Monad { // type constructor: pass an 'a', get back an 'M a' template struct Rep { typedef Type; }; // type deconstructor: pass an 'M a', get back an 'a' template struct UnRep { typedef Type; }; } and also template <> struct MonadTraitsSpecializer< RepType > { typedef Monad; // the monad concept class }; ////////////////////////////// // Monad zeros enable comprehension guards to work concept MonadWithZero models Monad { // zero :: m a typedef Zero; // a value type static Zero zero; } ////////////////////////////// // Some monads have pluses concept MonadWithPlus models Monad { // plus :: m a -> ma -> ma typedef Plus; // a full functoid type static Plus plus; } */ ////////////////////////////////////////////////////////////////////// struct ListM { template struct Rep { typedef List Type; }; template struct UnRep { typedef typename MA::ElementType Type; }; struct XUnit { template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const A& x ) const { return cons(x,NIL); } }; typedef Full1 Unit; static Unit unit; struct XBind { template struct Sig : public FunType::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { return concat( map(k,m) ); } }; typedef Full2 Bind; static Bind bind; typedef AUniqueTypeForNil Zero; static Zero zero; typedef Cat Plus; // cat is monad plus for lists static Plus plus; // FIX THIS maybe: map/join/bind_ could be implemented here as // well. default implementations could be inherited. Not clear if // it gains anything, since you can just call the "free function" // versions of them, which have defaults based on unit/bind. }; FCPP_MAYBE_DEFINE(ListM::Unit ListM::unit;) FCPP_MAYBE_DEFINE(ListM::Bind ListM::bind;) FCPP_MAYBE_DEFINE(ListM::Zero ListM::zero;) template struct MonadTraitsSpecializer > { typedef ListM Monad; }; template struct MonadTraitsSpecializer > { typedef ListM Monad; }; ////////////////////////////////////////////////////////////////////// struct MaybeM { template struct Rep { typedef Maybe Type; }; template struct UnRep { typedef typename MA::ElementType Type; }; typedef Just Unit; static Unit unit; struct XBind { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { if( m.is_nothing() ) return NOTHING; else return k( m.value() ); } }; typedef Full2 Bind; static Bind bind; typedef AUniqueTypeForNothing Zero; static Zero zero; struct XPlus { template struct Sig : public FunType {}; template typename Sig::ResultType operator()( const MA& x, const MA2& y ) const { if( x.is_nothing() ) return y; return x; } }; typedef Full2 Plus; static Plus plus; }; FCPP_MAYBE_DEFINE(MaybeM::Unit MaybeM::unit;) FCPP_MAYBE_DEFINE(MaybeM::Bind MaybeM::bind;) FCPP_MAYBE_DEFINE(MaybeM::Zero MaybeM::zero;) template struct MonadTraitsSpecializer > { typedef MaybeM Monad; }; ////////////////////////////////////////////////////////////////////// struct IdentityM { // M a = a typedef Id Unit; static Unit unit; struct XBind { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { return k(m); } }; typedef Full2 Bind; static Bind bind; }; FCPP_MAYBE_DEFINE(IdentityM::Unit IdentityM::unit;) FCPP_MAYBE_DEFINE(IdentityM::Bind IdentityM::bind;) ////////////////////////////////////////////////////////////////////// template struct StateM { // M a = State -> (a,State) struct XUnit { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const A& a ) const { return makePair(a); } }; typedef Full1 Unit; static Unit unit; struct XBind { template struct Sig : public FunType,LET > >, CALL > >, CALL > > > > >::Type > {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { // \s0 -> let (a,s1) = m s0 // (b,s2) = k a s1 // in (b,s2) LambdaVar<1> P; LambdaVar<2> s0; return lambda(s0)[ let[ P == m[s0] ].in[ k[fst[P]][snd[P]] ] ]; } }; typedef Full2 Bind; static Bind bind; static typename LEType< LAM,CALL,State> > >::Type assign( const State& sp ) { LambdaVar<1> s; return lambda(s)[ makePair[empty][sp] ]; } static typename LEType< LAM,CALL,LV<1> > > >::Type fetch() { LambdaVar<1> s; return lambda(s)[ makePair[s,s] ]; } }; template typename StateM::Unit StateM::unit; template typename StateM::Bind StateM::bind; ////////////////////////////////////////////////////////////////////// // liftM, liftM2, liftM3 (as in Haskell) namespace impl { template struct XLiftM { template struct Sig : public FunType,COMP >,GETS<2,LV<1> > > > >::Type> {}; template typename Sig::ResultType operator()( const F& f ) const { LambdaVar<1> X; LambdaVar<2> X_; return lambda(X)[ compM()[ f[X_] | X_ <= X ] ]; } }; } template Full1 > liftM() { return makeFull1( impl::XLiftM() ); } template struct LiftM { typedef Full1 > Type; }; namespace impl { template struct XLiftM2 { template struct Sig : public FunType,LV<3>,COMP,LV<4> >,GETS<2,LV<1> >,GETS<4,LV<3> > > > >::Type> {}; template typename Sig::ResultType operator()( const F& f ) const { LambdaVar<1> X; LambdaVar<2> X_; LambdaVar<3> Y; LambdaVar<4> Y_; return lambda(X,Y)[ compM()[ f[X_,Y_] | X_ <= X, Y_ <= Y ] ]; } }; } template Full1 > liftM2() { return makeFull1( impl::XLiftM2() ); } template struct LiftM2 { typedef Full1 > Type; }; namespace impl { template struct XLiftM3 { template struct Sig : public FunType,LV<3>,LV<5>,COMP,LV<4>,LV<6> >,GETS<2,LV<1> >,GETS<4,LV<3> >,GETS<6,LV<5> > > > >::Type> {}; template typename Sig::ResultType operator()( const F& f ) const { LambdaVar<1> X; LambdaVar<2> X_; LambdaVar<3> Y; LambdaVar<4> Y_; LambdaVar<5> Z; LambdaVar<6> Z_; return lambda(X,Y,Z)[ compM()[ f[X_,Y_,Z_] | X_ <= X, Y_ <= Y, Z_ <= Z ] ]; } }; } template Full1 > liftM3() { return makeFull1( impl::XLiftM3() ); } template struct LiftM3 { typedef Full1 > Type; }; ////////////////////////////////////////////////////////////////////// // The ByNeed monad, for "lazifying" computations template struct ByNeedImpl { void incref() const { ++refC_; } void decref() const { if (!--refC_) delete this; } private: mutable RefCountType refC_; typedef union { unsigned char val[ sizeof(T) ]; // The real variable // a bunch of dummies of every conceivable type long z1, *pz1; long double z2, *pz2; void *z3, **pz3; impl::misc_types::PtrToFxn z4, *pz4; impl::misc_types::Argh *pz5; int z6, *pz6; char z7, *pz7; double z8, *pz8; impl::misc_types::PtrToMember z9, *pz9; impl::misc_types::PtrToMemberFxn z10, *pz10; } U; mutable U u; mutable Fun0 fxn; mutable bool val_is_valid; // FIX THIS: can optimize this away into fxn const T& value() const { return *static_cast(static_cast(&u.val)); } T& value() { return *static_cast(static_cast(&u.val)); } void init( const T& x ) const { new (static_cast(&u.val)) T(x); } static T dummyT() { throw fcpp_exception("Used invalid fxn in ByNeedImpl"); } static Fun0 dummy() { static Fun0 f( ptr_to_fun(&ByNeedImpl::dummyT) ); return f; } // No copy/assignment ByNeedImpl( const ByNeedImpl& ); void operator=( const ByNeedImpl& ); public: typedef T ElementType; ByNeedImpl( const T& x ) : refC_(0), fxn( dummy() ), val_is_valid(true) { init(x); } ByNeedImpl( Fun0 f ) : refC_(0), fxn( f ), val_is_valid(false) {} const T& force() const { if( val_is_valid ) return value(); else { init( fxn() ); val_is_valid = true; return value(); } } }; template class ByNeed { IRef > ref; public: typedef T ElementType; ByNeed( const T& x ) : ref( new ByNeedImpl(x) ) {} ByNeed( Fun0 f ) : ref( new ByNeedImpl(f) ) {} // default copy constructor and assignment operator are fine const T& force() const { return ref->force(); } }; namespace impl { struct XBForce { template struct Sig : FunType {}; template const T& operator()( const ByNeed& bt ) const { return bt.force(); } }; } typedef Full1 BForce; FCPP_MAYBE_EXTERN BForce bForce; namespace impl { struct XBDelay { template struct Sig : FunType > {}; template ByNeed operator()( const T& x ) const { return ByNeed( x ); } }; } typedef Full1 BDelay; FCPP_MAYBE_EXTERN BDelay bDelay; // bLift lazily lifts a function's results into the ByNeed monad: // bLift :: (a -> b) -> a -> ByNeed b // bLift(f)(args) == ByNeed( lambda()[ f[args] ] ) namespace impl{ template class XBLifter0 : public CFunType::ResultType> > { F f; public: XBLifter0( const F& ff ) : f(ff) {} ByNeed::ResultType> operator()() const { return ByNeed::ResultType>( lambda()[ f[_*_] ] ); } }; template class XBLifter1 { F f; public: XBLifter1( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType> > {}; template typename Sig::ResultType operator()( const X& x ) const { return typename Sig::ResultType( lambda()[ f[x] ] ); } }; template class XBLifter2 { F f; public: XBLifter2( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType> > {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return typename Sig::ResultType( lambda()[ f[x][y] ] ); } }; template class XBLifter3 { F f; public: XBLifter3( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType> > {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { return typename Sig::ResultType( lambda()[ f[x][y][z] ] ); } }; class XBLift { template struct Helper; template struct Helper<0,F> { typedef Full0 > Result; static Result go( const F& f ) { return makeFull0( XBLifter0(f) ); } }; template struct Helper<1,F> { typedef Full1 > Result; static Result go( const F& f ) { return makeFull1( XBLifter1(f) ); } }; template struct Helper<2,F> { typedef Full2 > Result; static Result go( const F& f ) { return makeFull2( XBLifter2(f) ); } }; template struct Helper<3,F> { typedef Full3 > Result; static Result go( const F& f ) { return makeFull3( XBLifter3(f) ); } }; public: template struct Sig : public FunType::max_args,F>::Result> {}; template typename Sig::ResultType operator()( const F& f ) const { return Helper::max_args,F>::go( f ); } }; } typedef Full1 BLift; FCPP_MAYBE_EXTERN BLift bLift; struct ByNeedM { template struct Rep { typedef ByNeed Type; }; template struct UnRep { typedef typename MA::ElementType Type; }; struct XUnit { template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const A& x ) const { return ByNeed( x ); } }; typedef Full1 Unit; static Unit unit; struct XBind { template struct Sig : public FunType::ResultType > {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { typedef typename Sig::ResultType Res; return Res( lambda()[ bForce[ k[ bForce[ m ] ] ] ] ); //return k( bForce( m ) ); } }; typedef Full2 Bind; static Bind bind; }; FCPP_MAYBE_DEFINE(ByNeedM::Unit ByNeedM::unit;) FCPP_MAYBE_DEFINE(ByNeedM::Bind ByNeedM::bind;) template struct MonadTraitsSpecializer > { typedef ByNeedM Monad; }; } // end namespace fcpp #endif