5
\$\begingroup\$

Have I defined a Monad object for C++? Below is a class called var which I created years ago to implement a lambda calculus like interpreter in C++. The class defaults to a value of nothing. If assigned a value, the behavior invoked during runtime is defined by the data type assigned to the value of var. Through polymorphism the correct function is called. Within the function other instances of var can be cast to the desired data type. Resulting in a null pointer if cast to the incorrect type.

After reading up on Monads, it looks like the var class defined the behavior associated with Monads.

Also, I am very interested in any feedback on how to improve the class. Some aras of concern:

  • Returning a double to manage partial ordering from the comp method.
  • Returning typeid(self).name(); as the default behavior.
  • Should default behaviour be invoked for classes that do not overwrite var friend functions.
  • Is there any way to break up the implimentation from the header? Every time I try, there are always link issues were the associated type's function is missing.

Thank you in advance for any help offered!

Note: the entire code base is too big to be included here in its entirty; a repo, is here. Class var was renamed from class let in another incarnation, so as to be more meaningful in C++ code context. While it is a WIP, the entire class is below, to ensure the context of this question doesn't change over time.

namespace Olly {

    class var {
        struct interface_type;

    public:

        var();
        template <typename T> var(T  x);

        friend std::ostream& operator<<(std::ostream& stream, var n);

        template <typename T> std::shared_ptr<const T>  cast()       const;  // Cast the object as an instance of the specified type.
        template <typename T>                        T  copy()       const;  // Get a copy of the objects as a specified type.

        Text              type()                    const;  // The class generated type name.
        Text               cat()                    const;  // The class generated category name.
        bool                is()                    const;  // Is or is not the object defined.
        void               str(Text_Stream& out)    const;  // String representation of the object.
        void              repr(Text_Stream& out)    const;  // Recreatable text representation of an object.

        operator bool()                             const;

        double            comp(var n)               const;  // Compare two objects. 0 = equality, > 0 = grater than, < 0 = less than, NAN = not same type.
        bool                eq(var n)               const;  // Equal to.
        bool                ne(var n)               const;  // Not equal to.
        bool                ge(var n)               const;  // Greater than equal to.
        bool                le(var n)               const;  // Less than equal to.
        bool                gt(var n)               const;  // Greater than.
        bool                lt(var n)               const;  // Less than.

        bool    operator==(var n)                   const;
        bool    operator!=(var n)                   const;
        bool    operator>=(var n)                   const;
        bool    operator> (var n)                   const;
        bool    operator<=(var n)                   const;
        bool    operator< (var n)                   const;

        var              b_and(var n)               const;  // Binary and.
        var               b_or(var n)               const;  // Binary or.
        var              b_xor(var n)               const;  // Binary exclusive or.
        var              b_neg()                    const;  // Binary negation.

        var         operator&(var n)                const;
        var         operator|(var n)                const;
        var         operator^(var n)                const;
        var         operator~()                     const;

        var              u_add()                    const;  // Addition identity.
        var              u_neg()                    const;  // Unary compliment.

        var                add(var n)               const;  // Addition.
        var                sub(var n)               const;  // Subtraction.
        var                mul(var n)               const;  // Multiplication.
        var                div(var n)               const;  // Division.
        var                mod(var n)               const;  // Modulus.

        var          operator+()                    const;
        var          operator-()                    const;

        var          operator+(var n)               const;
        var          operator-(var n)               const;
        var          operator*(var n)               const;
        var          operator/(var n)               const;
        var          operator%(var n)               const;

        var              f_div(var n)               const;  // Floor divide.
        var                rem(var n)               const;  // Remainder.
        var                pow(var n)               const;  // Raise to the power of.
        var               root(var n)               const;  // Reduce to the root of.

        bool               has(var n)               const;  // Determine if an object has an element.
        std::size_t       size()                    const;  // Size of an object.
        var               front()                   const;  // Lead element of an object.
        var               back()                    const;  // Last element of an object.
        var               place(var n)              const;  // Place an object as the front element.
        var               push(var n)               const;  // Place an object as the front element.
        var               next()                    const;  // Remove the front element from an object.
        var               prev()                    const;  // Remove the front element from an object.

        var         operator>>(std::size_t shift)   const;
        var         operator<<(std::size_t shift)   const;

        var                get(var key)             const;  // Get an element from a collection.
        var                set(var key, var val)    const;  // Set the value of an element in a collection.
        var                del(var key)             const;  // Delete an element from a collection.

        var            reverse()                    const;  // Reverse the order of an object's elements.

        std::size_t       hash()                    const;  // Get the hash of an object.
        OP_CODE        op_code()                    const;
        bool        is_nothing()                    const;
        bool      is_something()                    const;
        Text              help()                    const;  // Define a string description of the object.

        // TODO: add capture of arguments to pass to a function.
        // TODO: figure out how to incorporate expression iteration.

    private:

        struct interface_type {

            /********************************************************************************************/
            //
            //                              'interface_type' Class Definition
            //
            //       A simple interface description allowing redirection of the 'var' data type.
            //
            /********************************************************************************************/

            virtual ~interface_type() {};

            virtual operator bool()                           const = 0;

            virtual Text            _type()                   const = 0;
            virtual Text            _cat()                    const = 0;
            virtual bool            _is()                     const = 0;
            virtual void            _str(Text_Stream& out)    const = 0;
            virtual void            _repr(Text_Stream& out)   const = 0;

            virtual double          _comp(var n)              const = 0;

            virtual var             _b_and(var n)             const = 0;
            virtual var             _b_or(var n)              const = 0;
            virtual var             _b_xor(var n)             const = 0;
            virtual var             _b_neg()                  const = 0;

            virtual var             _u_add()                  const = 0;
            virtual var             _u_neg()                  const = 0;

            virtual var             _add(var n)               const = 0;
            virtual var             _sub(var n)               const = 0;
            virtual var             _mul(var n)               const = 0;
            virtual var             _div(var n)               const = 0;
            virtual var             _mod(var n)               const = 0;

            virtual var             _f_div(var n)             const = 0;
            virtual var             _rem(var n)               const = 0;
            virtual var             _pow(var n)               const = 0;
            virtual var             _root(var n)              const = 0;

            virtual bool            _has(var n)               const = 0;
            virtual std::size_t     _size()                   const = 0;
            virtual var             _front()                  const = 0;
            virtual var             _back()                   const = 0;
            virtual var             _place(var n)             const = 0;
            virtual var             _push(var n)              const = 0;
            virtual var             _next()                   const = 0;
            virtual var             _prev()                   const = 0;

            virtual var             _reverse()                const = 0;

            virtual var             _get(var key)             const = 0;
            virtual var             _set(var key, var val)    const = 0;
            virtual var             _del(var key)             const = 0;

            virtual std::size_t     _hash()                   const = 0;
            virtual Text            _help()                   const = 0;
            virtual bool            _is_nothing()             const = 0;
            virtual OP_CODE         _op_code()                const = 0;
        };

        template <typename T>
        struct data_type : interface_type {

            /******************************************************************************************/
            //
            //                                 'data_type' Class Definition
            //
            //             The interface implementation of the 'interface_type' data type.
            //             Defining a shared const pointer of the data type passed to it.
            //
            /******************************************************************************************/

            data_type(T val);
            virtual ~data_type();

            operator bool()                           const;

            Text            _type()                   const;
            Text            _cat()                    const;
            bool            _is()                     const;
            void            _str(Text_Stream& out)    const;
            void            _repr(Text_Stream& out)   const;

            double          _comp(var n)              const;

            var             _b_and(var n)             const;
            var             _b_or(var n)              const;
            var             _b_xor(var n)             const;
            var             _b_neg()                  const;

            var             _u_add()                  const;
            var             _u_neg()                  const;

            var             _add(var n)               const;
            var             _sub(var n)               const;
            var             _mul(var n)               const;
            var             _div(var n)               const;
            var             _mod(var n)               const;

            var             _f_div(var n)             const;
            var             _rem(var n)               const;
            var             _pow(var n)               const;
            var             _root(var n)              const;

            bool            _has(var n)               const;
            std::size_t     _size()                   const;
            var             _front()                  const;
            var             _back()                   const;
            var             _place(var n)             const;
            var             _push(var n)              const;
            var             _next()                   const;
            var             _prev()                   const;

            var             _get(var key)             const;
            var             _set(var key, var val)    const;
            var             _del(var key)             const;

            var             _reverse()                const;
             
            std::size_t     _hash()                   const;
            Text            _help()                   const;
            bool            _is_nothing()             const;
            OP_CODE         _op_code()                const;

            T              _data;
        };

        std::shared_ptr<const interface_type> _ptr;
    };



    /********************************************************************************************/
    //
    //                                 'nothing' Class Definition
    //
    //          A basic class definition of the value of nothing.  This is used within
    //          'var' class implementation to return a result of nothing for results
    //          which have either conflicting types, or in some cases as the default to
    //          return unless overridden.
    //
    //          This class also demonstrates the basic function methods that should be
    //          over written for proper object behavior.
    //
    /********************************************************************************************/

    class nothing {

    public:

        friend Text          _type_(const nothing& self);
        friend bool            _is_(const nothing& self);
        friend double        _comp_(const nothing& self, var n);

        friend void           _str_(Text_Stream& out, const nothing& self);
        friend void          _repr_(Text_Stream& out, const nothing& self);

        friend bool    _is_nothing_(const nothing& self);
    };



    /********************************************************************************************/
    //
    //                                Support Function Declarations
    //
    //          These definitions add a few useful and some necessary support functions.
    //
    /********************************************************************************************/

    Text  str(var a);          // Convert any 'var' to a Text.
    Text repr(var a);          // Convert any 'var' to a Text representation of the 'var'.

    var pop_front(var& exp);    // Remove and return the front element from an ordered expression.
    var pop_back(var& exp);    // Remove and return the back element from an ordered expression.



    /********************************************************************************************/
    //
    //                      'var' Class Function Default Template API.
    //
    //           The following function templates define the over-ridable functions which
    //           may be used to tailor the behavior of any object held within a 'var'.
    //
    //           Each function defined here defines the default behavior of each function
    //           which is invoked if a function is not overwritten for a defined class.
    //
    /********************************************************************************************/

    template<typename T>            /****  Type Name  ****/
    Text _type_(const T& self);

    template<typename T>
    Text _type_(const T& self) {
        return typeid(self).name();
    }


    template<typename T>            /****  Category Name  ****/
    Text _cat_(const T& self);

    template<typename T>
    Text _cat_(const T& self) {
        return "uncategorized";
    }


    template<typename T>            /****  Boolean Conversion  ****/
    bool _is_(const T& self);

    template<typename T>
    bool _is_(const T& self) {
        return false;
    }


    template<typename T>            /****  String Conversion  ****/
    void _str_(Text_Stream& out, const T& self);

    template<typename T>
    void _str_(Text_Stream& out, const T& self) {

        // TODO: handle object based on stream availability.
        // 
        constexpr bool n = is_streamable<std::stringstream, T>::value;

        //if (n) {
        //    out << self;
        //}
        //else {
        //    out << "object<" << &self << "," << _type_(self) << ">";
        //}

        out << "object<" << &self << "," << _type_(self) << ">";

        //out << self;
    }


    template<typename T>            /****  String Representation  ****/
    void _repr_(Text_Stream& out, const T& self);

    template<typename T>
    void _repr_(Text_Stream& out, const T& self) {
        out << str(nothing());
    }


    template<typename T>            /****  Comparison Between Variables  ****/
    double _comp_(const T& self, var other);

    template<typename T>
    double _comp_(const T& self, var other) {
        return NOT_A_NUMBER;
    }


    template<typename T>            /****  Logical Conjunction  ****/
    var _b_and_(const T& self, var other);

    template<typename T>
    var _b_and_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Logical Inclusive Disjunction  ****/
    var _b_or_(const T& self, var other);

    template<typename T>
    var _b_or_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Logical Exclusive Disjunction  ****/
    var _b_xor_(const T& self, var other);

    template<typename T>
    var _b_xor_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Negation  ****/
    var _b_neg_(const T& self);

    template<typename T>
    var _b_neg_(const T& self) {
        return self;
    }


    template<typename T>            /****  Unary Addition  ****/
    var _u_add_(const T& self);

    template<typename T>
    var _u_add_(const T& self) {
        return var();
    }


    template<typename T>            /****  Unary Compliment  ****/
    var _u_neg_(const T& self);

    template<typename T>
    var _u_neg_(const T& self) {
        return var();
    }


    template<typename T>            /****  Addition or Concatenation  ****/
    var _add_(const T& self, var other);

    template<typename T>
    var _add_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Subtraction or Division  ****/
    var _sub_(const T& self, var other);

    template<typename T>
    var _sub_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Multiplication  ****/
    var _mul_(const T& self, var other);

    template<typename T>
    var _mul_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Division  ****/
    var _div_(const T& self, var other);

    template<typename T>
    var _div_(const T& self, var other) {
        return var();
    }

    template<typename T>            /****  Modulation  ****/
    var _mod_(const T& self, var other);

    template<typename T>
    var _mod_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Floor Division  ****/
    var _f_div_(const T& self, var other);

    template<typename T>
    var _f_div_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Remainder  ****/
    var _rem_(const T& self, var other);

    template<typename T>
    var _rem_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Raise to Power of  ****/
    var _pow_(const T& self, var other);

    template<typename T>
    var _pow_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Reduce to Power of  ****/
    var _root_(const T& self, var other);

    template<typename T>
    var _root_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Check if an object has an element  ****/
    bool _has_(const T& self, var other);

    template<typename T>
    bool _has_(const T& self, var other) {
        return false;
    }


    template<typename T>            /****  Length Of  ****/
    std::size_t _size_(const T& self);

    template<typename T>
    std::size_t _size_(const T& self) {
        return 0;
    }


    template<typename T>            /****  Lead Element Of  ****/
    var _front_(const T& self);

    template<typename T>
    var _front_(const T& self) {
        return var();
    }


    template<typename T>            /****  Lead Element Of  ****/
    var _back_(const T& self);

    template<typename T>
    var _back_(const T& self) {
        return var();
    }


    template<typename T>            /**** Prepend Lead Element Of  ****/
    var _place_(const T& self, var other);

    template<typename T>
    var _place_(const T& self, var other) {
        return var();
    }


    template<typename T>            /**** Prepend Lead Element Of  ****/
    var _push_(const T& self, var other);

    template<typename T>
    var _push_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Drop The Leading Element  ****/
    var _next_(const T& self);

    template<typename T>
    var _next_(const T& self) {
        return var();
    }


    template<typename T>            /****  Drop The Leading Element  ****/
    var _prev_(const T& self);

    template<typename T>
    var _prev_(const T& self) {
        return var();
    }


    template<typename T>            /****  Reverse The Elements Of  ****/
    var _reverse_(const T& self);

    template<typename T>
    var _reverse_(const T& self) {
        return var();
    }


    template<typename T>            /****  Retrieve A Selection From  ****/
    var _get_(const T& self, var other);

    template<typename T>
    var _get_(const T& self, var other) {
        return var();
    }


    template<typename T>            /****  Set A Selection Of  ****/
    var _set_(const T& self, var other, var val);

    template<typename T>
    var _set_(const T& self, var other, var val) {
        return var();
    }


    template<typename T>            /****  Remove A Selection From  ****/
    var _del_(const T& self, var other);

    template<typename T>
    var _del_(const T& self, var other) {
        return var();
    }

    template<typename T>            /****  Hash Value  ****/
    std::size_t _hash_(const T& self);

    template<typename T>
    std::size_t _hash_(const T& self) {
        return DEFAULT_HASH_FUNCTION(repr(self));
    }


    template<typename T>            /****  Return An Operation Code ****/
    OP_CODE _op_code_(const T& self);

    template<typename T>
    OP_CODE _op_code_(const T& self) {
        return OP_CODE::nothing_op;
    }


    template<typename T>            /****  Determine If A Var Is Undefined ****/
    bool _is_nothing_(const T& self);

    template<typename T>
    bool _is_nothing_(const T& self) {
        return false;
    }


    template<typename T>            /****  Return A Help String ****/
    Text _help_(const T& self);

    template<typename T>
    Text _help_(const T& self) {
        return "No object documentation available.";
    }


    std::ostream& operator<<(std::ostream& stream, var n) {

        Text_Stream out;

        out.copyfmt(stream);

        n.str(out);

        stream << out.str();

        return stream;
    }




    /********************************************************************************************/
    //
    //                                 'nothing' Class Implementation
    //
    /********************************************************************************************/

    Text _type_(const nothing& self) {
        return "nothing";
    }

    bool _is_(const nothing& self) {
        return false;
    }

    double _comp_(const nothing& self, var n) {
        return NOT_A_NUMBER;
    }

    void _str_(Text_Stream& out, const nothing& self) {
        out << "nothing";
    }

    void _repr_(Text_Stream& out, const nothing& self) {
        out << "nothing";
    }

    bool _is_nothing_(const nothing& self) {
        return true;
    }




    /********************************************************************************************/
    //
    //                                'var' Class Implementation
    //
    /********************************************************************************************/

    var::var() : _ptr(std::make_shared<data_type<nothing>>(nothing())) {
    }

    template <typename T>
    var::var(T x) : _ptr(std::make_shared<data_type<T>>(x)) {
    }

    template <typename T>
    std::shared_ptr<const T> var::cast() const {

        auto p = std::dynamic_pointer_cast<const data_type<T>>(_ptr);

        if (p == nullptr) {
            return nullptr;
        }

        return std::shared_ptr<const T>(p, &(p->_data));
    }

    template <typename T> 
    T var::copy() const {

        auto p = std::dynamic_pointer_cast<const data_type<T>>(_ptr);

        if (p) {
            return T{ *p };
        }

        return T{};
    }

    Text var::type() const {
        return _ptr->_type();
    }

    Text var::cat() const {
        return _ptr->_cat();
    }

    bool var::is() const {
        return const_cast<interface_type*>(_ptr.get())->_is();
    }

    void var::str(Text_Stream& out) const {
        _ptr->_str(out);
    }

    void var::repr(Text_Stream& out) const {
        _ptr->_repr(out);
    }

    double var::comp(var n) const {
        return _ptr->_comp(n);
    }

    bool var::eq(var n) const {
        return (comp(n) == 0.0 ? true : false);
    }

    bool var::ne(var n) const {
        return (comp(n) != 0.0 ? true : false);
    }

    bool var::ge(var n) const {
        return (comp(n) >= 0.0 ? true : false);
    }

    bool var::le(var n) const {
        return (comp(n) <= 0.0 ? true : false);
    }

    bool var::gt(var n) const {
        return (comp(n) > 0.0 ? true : false);
    }

    bool var::lt(var n) const {
        return (comp(n) < 0.0 ? true : false);
    }

    var var::b_and(var n) const {
        return _ptr->_b_and(n);
    }

    var var::b_or(var n) const {
        return _ptr->_b_or(n);
    }

    var var::b_xor(var n) const {
        return _ptr->_b_xor(n);
    }

    var var::b_neg() const {
        return _ptr->_b_neg();
    }

    var var::operator&(var n) const {
        return b_and(n);
    }

    var var::operator|(var n) const {
        return b_or(n);
    }

    var var::operator^(var n) const {
        return b_xor(n);
    }

    var var::operator~() const {
        return b_neg();
    }

    var var::u_add() const {
        return _ptr->_u_add();
    }

    var var::u_neg() const {
        return _ptr->_u_neg();
    }

    var var::add(var n) const {
        return _ptr->_add(n);
    }

    var var::sub(var n) const {
        return _ptr->_sub(n);
    }

    var var::mul(var n) const {
        return _ptr->_mul(n);
    }

    var var::div(var n) const {
        return _ptr->_div(n);
    }

    var var::mod(var n) const {
        return _ptr->_mod(n);
    }

    var var::operator+() const {
        return u_add();
    }

    var var::operator-() const {
        return u_neg();
    }

    var var::f_div(var n) const {
        return _ptr->_f_div(n);
    }

    var var::rem(var n) const {
        return _ptr->_rem(n);
    }

    var var::pow(var n) const {
        return _ptr->_pow(n);
    }

    var var::root(var n) const {
        return _ptr->_root(n);
    }

    bool var::has(var n) const {
        return _ptr->_has(n);
    }

    std::size_t var::size() const {
        return _ptr->_size();
    }

    var var::front() const {
        return _ptr->_front();
    }

    var var::back() const {
        return _ptr->_back();
    }

    var var::place(var n) const {
        return _ptr->_place(n);
    }

    var var::push(var n) const {
        return _ptr->_push(n);
    }

    var var::next() const {
        return _ptr->_next();
    }

    var var::prev() const {
        return _ptr->_prev();
    }

    var var::operator>>(std::size_t shift) const {

        var a{ *this };

        while (shift--) {

            a = a.next();
        }

        return a;
    }

    var var::operator<<(std::size_t shift) const {

        var a{ *this };

        while (shift--) {
            a = a.prev();
        }

        return a;
    }

    var var::reverse() const {
        return _ptr->_reverse();
    }

    var var::get(var n) const {
        return _ptr->_get(n);
    }

    var var::set(var n, var val) const {
        return _ptr->_set(n, val);
    }

    var var::del(var n) const {
        return _ptr->_del(n);
    }

    std::size_t var::hash() const {
        return _ptr->_hash();
    }

    OP_CODE var::op_code() const {
        return _ptr->_op_code();
    }

    bool var::is_nothing() const {
        return _ptr->_is_nothing();
    }

    bool var::is_something() const {
        return !_ptr->_is_nothing();
    }

    Text var::help() const {
        return _ptr->_help();
    }

    var::operator bool() const {
        return is();
    }

    bool var::operator==(var n) const {
        return eq(n);
    }

    bool var::operator!=(var n) const {
        return ne(n);
    }

    bool var::operator>=(var n) const {
        return ge(n);
    }

    bool var::operator> (var n) const {
        return gt(n);
    }

    bool var::operator<=(var n) const {
        return le(n);
    }

    bool var::operator< (var n) const {
        return lt(n);
    }

    var var::operator+(var n) const {
        return add(n);
    }

    var var::operator-(var n) const {
        return sub(n);
    }

    var var::operator*(var n) const {
        return mul(n);
    }

    var var::operator/(var n) const {
        return div(n);
    }

    var var::operator%(var n) const {
        return mod(n);
    }




    /********************************************************************************************/
    //
    //                                'data_type' Class Implementation
    //
    /********************************************************************************************/

    template <typename T>
    var::data_type<T>::data_type(T val) : _data(std::move(val)) {
    }

    template<typename T>
    var::data_type<T>::~data_type() {
    }

    template <typename T>
    var::data_type<T>::operator bool() const {
        return _is();
    }

    template <typename T>
    std::size_t var::data_type<T>::_hash() const {
        return _hash_(_data);
    }

    template <typename T>
    Text var::data_type<T>::_type() const {
        return _type_(_data);
    }

    template <typename T>
    Text var::data_type<T>::_cat() const {
        return _cat_(_data);
    }

    template <typename T>
    bool var::data_type<T>::_is() const {
        return _is_(_data);
    }

    template <typename T>
    void var::data_type<T>::_str(Text_Stream& out) const {
        _str_(out, _data);
    }

    template <typename T>
    void var::data_type<T>::_repr(Text_Stream& out) const {
        _repr_(out, _data);
    }

    template <typename T>
    double var::data_type<T>::_comp(var n) const {
        return _comp_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_b_and(var n) const {
        return _b_and_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_b_or(var n) const {
        return _b_or_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_b_xor(var n) const {
        return _b_xor_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_b_neg() const {
        return _b_neg_(_data);
    }

    template<typename T>
    inline var var::data_type<T>::_u_add() const {
        return _u_add_(_data);
    }

    template<typename T>
    inline var var::data_type<T>::_u_neg() const {
        return _u_neg_(_data);
    }

    template <typename T>
    var var::data_type<T>::_add(var n) const {
        return _add_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_sub(var n) const {
        return _sub_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_mul(var n) const {
        return _mul_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_div(var n) const {
        return _div_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_mod(var n) const {
        return _mod_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_f_div(var n) const {
        return _f_div_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_rem(var n) const {
        return _rem_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_pow(var n) const {
        return _pow_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_root(var n) const {
        return _root_(_data, n);
    }

    template <typename T>
    bool var::data_type<T>::_has(var n) const {
        return _has_(_data, n);
    }

    template <typename T>
    std::size_t var::data_type<T>::_size() const {
        return _size_(_data);
    }

    template <typename T>
    var var::data_type<T>::_front() const {
        return _front_(_data);
    }

    template <typename T>
    var var::data_type<T>::_back() const {
        return _back_(_data);
    }

    template <typename T>
    var var::data_type<T>::_place(var n) const {
        return _place_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_push(var n) const {
        return _push_(_data, n);
    }

    template <typename T>
    var var::data_type<T>::_next() const {
        return _next_(_data);
    }

    template <typename T>
    var var::data_type<T>::_prev() const {
        return _prev_(_data);
    }

    template <typename T>
    var var::data_type<T>::_reverse() const {
        return _reverse_(_data);
    }

    template <typename T>
    var var::data_type<T>::_get(var key) const {
        return _get_(_data, key);
    }

    template <typename T>
    var var::data_type<T>::_set(var key, var val) const {
        return _set_(_data, key, val);
    }

    template <typename T>
    var var::data_type<T>::_del(var key) const {
        return _del_(_data, key);
    }

    template <typename T>
    Text var::data_type<T>::_help() const {
        return _help_(_data);
    }

    template <typename T>
    bool var::data_type<T>::_is_nothing() const {
        return _is_nothing_(_data);
    }

    template <typename T>
    OP_CODE var::data_type<T>::_op_code() const {
        return _op_code_(_data);
    }




    /********************************************************************************************/
    //
    //                            Basic Primitive Implementations
    //
    /********************************************************************************************/

    Text str(var a) {
        /*
            Convert a 'var' to its string representation.
        */

        Text_Stream stream;

        stream << std::boolalpha;

        if (a.type() == "format") {
            /*
                The 'format' data type must be printed using
                its string representation, else it would only
                impart its formatting to the stream instead of
                being printed to it.
            */
            a.repr(stream);
        }
        else {
            a.str(stream);
        }

        return stream.str();
    }

    Text repr(var a) {
        /*
            Convert a 'var' to its representation as a string.
        */

        Text_Stream stream;

        stream << std::boolalpha;

        a.repr(stream);

        return stream.str();
    }

    var pop_front(var& exp) {

        var a = exp.front();

        exp = exp.next();

        return a;
    }

    var pop_back(var& exp) {

        var a = exp.back();

        exp = exp.prev();

        return a;
    }
}
```
\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

Answers to your questions.

Have I defined a Monad object for C++?

Yes. Despite the name and its association with pure functional programming languages, it's not really that special. You can write monads in C as well. Since you have a data type that wraps a value, you have a way to construct that data type from a value, and you have functions that act on the wrapped value and returns that data type again, you have fulfilled all the obligations of the definition of a monad.

  • Returning a double to manage partial ordering from the comp method.

Yes, that's unusual. I see you wanted a way to signal that two values are unequal but have no particular ordering, and I guess you chose double because it has a NAN value? C++20 introduced std::partial_ordering that you can use as the return value of a comparison function, which would be more appropriate. If you still want to rely on NAN, consider using float instead of double, as it will be a little more efficient.

  • Returning typeid(self).name(); as the default behavior.

If you are OK with _type_() returning typeid(self).name(), why do you need to be able to set a custom name? On the other hand, consider that the return value of std::type_info::name() is implementation defined and not guaranteed to be unique. It could return "nothing" for all types and that would be legal.

  • Should default behaviour be invoked for classes that do not overwrite var friend functions.

I think that's the definition of default behaviour? However, the default behaviour should of course match what that function claims to do. So an _add_(const T& self, var other) that just does return var() is not what you want. If you cannot provide reasonable default behaviour, don't provide it at all.

  • Is there any way to break up the implimentation from the header? Every time I try, there are always link issues were the associated type's function is missing.

Concrete types and functions can be forward declared in the header, and their implementation can be put in source files. For templates, that normally doesn't work; they will only be instantiated when they are used, and at that point the whole definition must be available to the compiler. You can use explicit template instantiation, but then you need to know all types you will ever use in your program up front.

This doesn't scale

I am not sure what the intended use case is of var(), but if you want it to be able to wrap any type and allow any operation on them, this approach just doesn't scale at all.

First, you only make available some functions for doing comparisons, arithmatic and list operations. What if you want to wrap a std::fstream and allow read() and write() operations? You'd have to add more member functions to var, to interface_type, and to potentially many classes that derive from interface_type.

Second, consider all the possible integer types, from 8 to 64 bits, signed and unsigned. If you want to allow adding any kind of integer to any other kind of integer, you would have to write 64 overloads for each binary operation. Add float and double, and you have to write 100 overloads.

\$\endgroup\$
1
  • \$\begingroup\$ thank you for the response! A few notes to your points: The class was original implicated before C++20. I think at this point I just need to revise it to meet that standard. That will address the double as a return to comp. Also, It isn't really meant to scale for all data types. Only the ones that have an overwritten class defined will scale. Though anything can be cast or copied from a var. It was originally used to implement the data types in an interpreter. So beyond, holding a variable, casting it or copying it, the usefulness is limited. Thanks again! \$\endgroup\$
    – StormCrow
    Commented Mar 30, 2023 at 17:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.