Juria의 매크로를 Rust로 다시 쓰는 느낌.
E₁_taylor64
.전체 설치
fn e1_taylor_coefficients(n: isize) -> Vec<f64> {
use natural_constants::math::euler_mascheroni;
if n < 0 {
panic!("n ≥ 0 is required");
}
if n == 0 {
return vec![];
}
if n == 1 {
return vec![-euler_mascheroni];
}
let mut term = 1.0;
let mut terms = vec![-euler_mascheroni, term];
for k in 2..=n {
let k = k as f64;
term = -term * (k - 1.0) / (k * k);
terms.push(term);
}
terms
}
fn evalpoly64_impl(ident: proc_macro2::Ident, coefficients: &[f64]) -> proc_macro2::TokenStream {
use quote::quote;
let mut code = quote::quote! { 0.0 };
let mut cs = coefficients.iter().copied().collect::<Vec<_>>();
cs.reverse();
for (i, c) in cs.into_iter().enumerate() {
code = if 0 == i {
quote! { #c as f64 }
} else {
quote! { #c as f64 + #ident * (#code) }
}
}
quote::quote! {{ let #ident = #ident as f64; #code }}
}
#[proc_macro]
pub fn e1_taylor64(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
use proc_macro2::{
TokenStream,
TokenTree::{Ident, Literal, Punct},
};
let input = TokenStream::from(input);
let vec = input.into_iter().collect::<Vec<_>>();
let (z, n) = match &vec[..] {
[Ident(z), Punct(_), Literal(n)] => (z, n.to_string().parse::<isize>().unwrap()),
_ => panic!("e1_taylor64 requires (ident, isize). eg let z = 2f64; e1_taylor64!(z, 12)"),
};
let c = e1_taylor_coefficients(n);
let ident = z.to_owned();
let pl = evalpoly64_impl(ident.clone(), &c);
let gen = quote::quote! {{
let t = #ident as f64;
let pl = #pl;
pl - t.log(std::f64::consts::E)
}};
gen.into()
}
주리아가 뭐예요?최근 수치 계산계 근처에서 주목받고 있는 것 같다.[1]
파이썬과 같은 동적 프로그래밍 언어는 C의 절반 정도의 우수한 속도가 특징이다.
LLVM을 사용한 것 같습니다. 실행 파일과 공유 라이브러리로 컴파일할 수 있습니다.
Scheme처럼 건강하고 강력한 매크로를 사용할 수 있습니다.
Rust로 쓸 때 겪는 어려움
정의할 수 있는 곳에 제한이 있어요.
수속형 매크로는
fn(TokenStream) -> TokenStream
의 형식이다정의하려면 프로그램 매크로만 공개하는 프로그램 라이브러리에 있어야 합니다.
결국 파일을 분할해야 한다는 얘기다.
eval 없음
Rust에 eval이 없음(REPL도 없음)
부분적으로 eval이 매개 변수를 만들려고 하는 Token Stream의 상황은 난감하다.
예를 들어, 고려
evalpoly64
의 매크로입니다.이것은 변수와 여러 정수를 바탕으로 코드를 생성하는 것이다.
let num = evalpoly64!(x, [1.0, 2.0, 3.0, 4.0]);
\begin{aligned}evalpoly(x, [1, 2, 3, 4]) &= x^3 + 2x^2 + 3x + 4\\\\
&= 4 + x (3 + x (2 + x))
\end{aligned}
전개 후
let num = 4.0 + x * (3.0 + x * (2.0 + x * 1.0));
마크로입니다.rules로 정의할 수도 있습니다.macro_rules! evalpoly64 {
( $i: ident ) => {
0.0
};
( $i: ident, [ $x:expr ] ) => {
$x
};
( $i: ident, [$h:expr, $( $x:expr ),+] ) => {
$h + $i * (evalpoly64!($i, [$($x),*]))
};
}
이거 수속형 매크로로 쓸게요.fn evalpoly64_impl(ident: proc_macro2::Ident, coefficients: &[f64]) -> proc_macro2::TokenStream {
use quote::quote;
let mut code = quote::quote! { 0.0 };
let mut cs = coefficients.iter().copied().collect::<Vec<_>>();
cs.reverse();
for (i, c) in cs.into_iter().enumerate() {
code = if 0 == i {
quote! { #c as f64 }
} else {
quote! { #c as f64 + #ident * (#code) }
}
}
quote::quote! {{ let #ident = #ident as f64; #code }}
}
#[proc_macro]
pub fn evalpoly64(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
use proc_macro2::{
TokenStream,
TokenTree::{Group, Ident, Literal, Punct},
};
let message = "evalpoly64 requires (ident, [f64]). eg let z = 2f64; evalpoly64!(z, [1, 2, 3])";
let input = TokenStream::from(input);
let vec = input.into_iter().collect::<Vec<_>>();
let (z, n) = match &vec[..] {
[Ident(z), Punct(_), Group(a)] => (z, a),
[Ident(z), Punct(_), Group(a), Punct(_)] => (z, a),
_ => panic!(message),
};
let ident = z.to_owned();
let mut list: Vec<f64> = vec![];
let mut lit = true;
for t in n.stream() {
if lit {
match t {
Literal(l) => list.push(l.to_string().parse().unwrap()),
_ => panic!(message),
}
} else {
match t {
Punct(_) => {}
_ => panic!(message),
}
}
lit = !lit;
}
let gen = evalpoly64_impl(ident, &list);
gen.into()
}
길다.하고 싶은 게
evalpoly64_impl
라는 내용이에요.TokenStream
로Ident
와&[f64]
를 얻기 위해서는 비교적 긴 코드가 필요하다.프로그램형 매크로 안에서 매크로를 펼쳐 Token Stream을 얻으려 했으나 포기하고 함수를 실행한 경우도 있었다.
(상기
evalpoly64
를 펼칠 수 없기 때문에 evalpoly64_impl
개작하였습니다)총결산
eval이 있으면 쓰기 쉬울 것 같아요.
매크로를 쓰지 않아도 최적화를 통해 같은 코드를 만들 수 있는 사람은 루스트와 비슷하다고 생각합니다.
각주
↩︎
Reference
이 문제에 관하여(Juria의 매크로를 Rust로 다시 쓰는 느낌.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/rithmety/articles/20201022-rust-macro-vs-julia-macro텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)