-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] Rust ports #18
Conversation
@dominikandreasseitz @kaosmicadei Here is a very naive attempt at porting lower level types for expressions. If you want to have a look (can't add multiple reviewers until it goes public). |
Suggestion. It would be possible to consider the whole expression + symbol as a single enum to preserve the monoid properties of addition and other operations. In the sense that:
That would make use num::Complex;
#[derive(Debug, PartialEq)]
pub enum Operator {
Add,
Mul,
Pow,
NonComm,
Call
}
#[derive(Debug, PartialEq)]
pub enum Numerical {
Int(i64),
Float(f64),
Complex(Complex<f64>),
}
#[derive(Debug, PartialEq)]
pub enum Expression {
Symbol(&'static str),
Value(Numerical),
Expr { head: Operator, args: Vec<Box<Expression>> },
} |
@kaosmicadei Makes sense. Lemme have a go at it. |
Naive question: would anything else than an enum break monoidal properties ? |
Quick comment @kaosmicadei. Would it make sense to move all boxing constructors to the convenience functions ? |
Based on https://doc.rust-lang.org/std/macro.vec.html we could do something like macro_rules! vbox {
() => { vec![] };
($elem:expr; $n:expr) => { vec![Box::new($elem); $n] };
($($x:expr),+ $(,)?) => { vec![$(Box::new($x)),*] };
} Actually, in our case, the second pattern could be omitted. |
The macro implementation. macro_rules! vbox {
() => { vec![] };
($($x:expr),+ $(,)?) => { vec![$(Box::new($x)),*] };
}
macro_rules! impl_binary_operator_for_expression {
($trait:ident, $method:ident, $operator:path) => {
impl $trait for Expression {
type Output = Self;
fn $method(self, other: Self) -> Self {
use Expression::*;
match (self, other) {
(Value(x), Value(y)) => Value(x.$method(y)),
(Expr {head: $operator, args: args_lhs}, Expr {head: $operator, args: args_rhs}) => {
let args = args_lhs.into_iter().chain(args_rhs.into_iter()).collect();
Expr{head: $operator, args}
},
(Expr {head: $operator, args: mut args_lhs}, rhs) => {
args_lhs.push(Box::new(rhs));
Expr {head: $operator, args: args_lhs}
},
(lhs, Expr {head: $operator, args: mut args_rhs}) => {
args_rhs.push(Box::new(lhs));
Expr {head: $operator, args: args_rhs}
},
(lhs, rhs) => Expr{head: $operator, args: vbox![lhs, rhs]},
}
}
}
};
($trait:ident, $method:ident, $operator:path, $inv:expr) => {
impl $trait for Expression {
type Output = Self;
fn $method(self, other: Self) -> Self {
use Expression::*;
match (self, other) {
(Value(x), Value(y)) => Value(x.$method(y)),
(lhs, rhs) => Expr {
head: $operator,
args: vbox![lhs, $inv(rhs)]
},
}
}
}
}
}
impl_binop!(Add, add, Operator::ADD);
impl_binop!(Mul, mul, Operator::MUL);
impl_binop!(Sub, sub, Operator:: ADD, |x: Expression| { x.neg() });
impl_binop!(Div, div, Operator:: ADD, |x: Expression| { x.pow(Expression::float(-1.0)) }); It requires the implementation of the |
It would also require the |
This one? |
Yes, I was on that one too. |
Closes #16