非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

式の計算電卓コマンド版(1)

C++ の調査(2) - 非専門的シンギュラリティー研究所」で『式の計算電卓』のコマンド版を作ろうとしていました。その後「C++ の調査(6) - 非専門的シンギュラリティー研究所」で仕様を決めて ChatGPT で作ってもらったものを動くように修正して、機能を追加したものを作りました。これを今後「C++ の調査(7) - 非専門的シンギュラリティー研究所」で調べたようにポインターのラッパークラスを作っていく予定です。

その前に大域関数として定義されているものを派生クラスに取り込んでいきます。

using Exprs = vector<shared_ptr<Expr>>;
using Env = map<string, shared_ptr<Expr>>;

// 式の型定義
class Expr : public enable_shared_from_this<Expr> {
public:
    virtual ~Expr() = default;
    virtual double eval(const Env& env) const = 0;
    virtual string to_string(int& pos) const = 0;
    string pos_string(int& pos) const {
        return "#" + std::to_string(pos++);
    }
    virtual void collect_subexpressions(Exprs& out) = 0;
    virtual shared_ptr<Expr> evaluate_once(Env& env) = 0;
    virtual shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr,
        int& current_index) = 0;
    // 外から使いやすいようにラップする関数
    shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr) {
        int current_index = 0;
        return replace_subexpression(index_to_replace, new_subexpr, current_index);
    }
};

class Number : public Expr {
    double value;
public:
    Number(double v) : value(v) {}
    double eval(const Env& env) const override { return value; }
    string to_string(int& pos) const override {
        return std::to_string(value) + pos_string(pos);
    }
    // 番号付きの部分式取得
    void collect_subexpressions(Exprs& out) override {
        out.push_back(shared_from_this());
    }
    // 部分式評価(定数なら簡約、変数なら展開)
    shared_ptr<Expr> evaluate_once(Env& env) override {
        return shared_from_this();
    }
    shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr,
        int& current_index) override {
        if (current_index == index_to_replace) {
            current_index++;
            return new_subexpr;
        }
        int this_index = current_index;
        current_index++;
        // Number や Variable は子を持たないのでそのまま返す
        return shared_from_this();
    }
};

class Variable : public Expr {
    string name;
public:
    Variable(string n) : name(std::move(n)) {}
    double eval(const Env& env) const override {
        if (env.count(name)) return env.at(name)->eval(env);
        throw runtime_error("Undefined variable: " + name);
    }
    string to_string(int& pos) const override {
        return name + pos_string(pos);
    }
    // 番号付きの部分式取得
    void collect_subexpressions(Exprs& out) override {
        out.push_back(shared_from_this());
    }

    // 部分式評価(定数なら簡約、変数なら展開)
    shared_ptr<Expr> evaluate_once(Env& env) override {
        if (env.count(name)) return env[name];
        return shared_from_this();
    }

    shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr,
        int& current_index) override {
        if (current_index == index_to_replace) {
            current_index++;
            return new_subexpr;
        }

        int this_index = current_index;
        current_index++;

        // Number や Variable は子を持たないのでそのまま返す
        return shared_from_this();
    }
};

class UnaryOp : public Expr {
    char op;
    shared_ptr<Expr> expr;
public:
    UnaryOp(char o, shared_ptr<Expr> e) : op(o), expr(std::move(e)) {}
    double eval(const Env& env) const override {
        double a = expr->eval(env);
        switch (op) {
        case '-': return -a;
        }
        throw runtime_error("Unknown operator");
    }
    string to_string(int& pos) const override {
        string pos_str = pos_string(pos);
        return op + "(" + expr->to_string(pos) + ")" + pos_str;
    }
    // 番号付きの部分式取得
    void collect_subexpressions(Exprs& out) override {
        out.push_back(shared_from_this());
        expr->collect_subexpressions(out);
    }

    // 部分式評価(定数なら簡約、変数なら展開)
    shared_ptr<Expr> evaluate_once(Env& env) override {
        auto sub = expr->evaluate_once(env);
        if (auto subnum = dynamic_pointer_cast<Number>(sub)) {
            double result = UnaryOp(op, subnum).eval(env);
            return make_shared<Number>(result);
        }
        return shared_from_this();
    }

    shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr,
        int& current_index) override {
        if (current_index == index_to_replace) {
            current_index++;
            return new_subexpr;
        }

        int this_index = current_index;
        current_index++;

        auto new_expr = expr->replace_subexpression(index_to_replace, new_subexpr, current_index);
        return make_shared<UnaryOp>(op, new_expr);
    }
};

class BinaryOp : public Expr {
    char op;
    shared_ptr<Expr> lhs, rhs;
public:
    BinaryOp(char o, shared_ptr<Expr> l, shared_ptr<Expr> r) : op(o), lhs(std::move(l)), rhs(std::move(r)) {}
    double eval(const Env& env) const override {
        double a = lhs->eval(env), b = rhs->eval(env);
        switch (op) {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        }
        throw runtime_error("Unknown operator");
    }
    string to_string(int& pos) const override {
        string pos_str = pos_string(pos);
        string left_str = lhs->to_string(pos);
        string right_str = rhs->to_string(pos);
        return "(" + left_str + " " + op + " " + right_str + ")" + pos_str;
    }
    // 番号付きの部分式取得
    void collect_subexpressions(Exprs& out) override {
        out.push_back(shared_from_this());
        lhs->collect_subexpressions(out);
        rhs->collect_subexpressions(out);
    }

    // 部分式評価(定数なら簡約、変数なら展開)
    shared_ptr<Expr> evaluate_once(Env& env) override {
        auto left = lhs->evaluate_once(env);
        auto right = rhs->evaluate_once(env);
        auto lnum = dynamic_pointer_cast<Number>(left);
        auto rnum = dynamic_pointer_cast<Number>(right);
        if (lnum && rnum) {
            double result = BinaryOp(op, left, right).eval(env);
            return make_shared<Number>(result);
        }
        return shared_from_this();
    }

    shared_ptr<Expr> replace_subexpression(
        int index_to_replace,
        const shared_ptr<Expr>& new_subexpr,
        int& current_index) override {
        if (current_index == index_to_replace) {
            current_index++;
            return new_subexpr;
        }

        int this_index = current_index;
        current_index++;

        auto new_lhs = lhs->replace_subexpression(index_to_replace, new_subexpr, current_index);
        auto new_rhs = rhs->replace_subexpression(index_to_replace, new_subexpr, current_index);
        return make_shared<BinaryOp>(op, new_lhs, new_rhs);
    }
};