Description
The autodiff
procedural macro correctly evaluates logic contained within the macro but cannot handle previously defined logic. Specifically, invoked functions and undefined method_ calls both fail to provide the system with enough information to process the contained logic.
Example
Writing the logic for the sigmoid function within the macro works.
use acme::autodiff;
fn main() {
let (x, y) = (1_f64, 2_f64);
assert!(autodiff!(x, 1.0 / (1.0 + (-x).exp())) == 0.1049935854035065);
}
However, invoking a function (or even non-described methods) fails to evaluate correctly since the parsed input fails to store any meaningful information about the function.
use acme::autodiff;
use acme::prelude::sigmoid;
fn main() {
let (x, y) = (1_f64, 2_f64);
assert!(autodiff!(x, sigmoid(x)) != 0.1049935854035065);
}
Methods
Traditional macro libraries and methods seem to lack explicit support for engaging with these objects. At initial glance, the problem may require using lower-level Rust libraries to interact with the compiler but support for this is also limited.
Extracting the logic from the SourceFile
One approach would be to use the span of the expression to locate the resource and extract the required information.
Option 2: Rewrite the logic as a #[proc_macro_attribute]
#[gradient]
pub fn multiply<A, B, C>(a: A, b: B) -> C
where
A: std::ops::Mul<B, Output = C>
{
a * b
}
By writing a #[proc_macro_attribute]
any implemented functions could have a gradient function automatically generated. One of the primary issues with this is that we still run into the issue at hand when any external logic is invoked at any point within the function definition.