[EDIT with const initialization]
It is also possible to compute factorial by using rust type system. Crate typenum allows that by recoding binary arithmetic on the basis of the type system:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d34eef48622363ca2096a246cd933554
use std::ops::{ Mul, Sub, };
use typenum::{
B1, Sub1, Prod, U0, U1, U2, U3, U4, U5, U20, U24, Unsigned, Bit, UInt
};
trait Fact {
type F: Unsigned;
}
impl Fact for U0 {
type F = U1;
}
impl<U: Unsigned, B: Bit> Fact for UInt<U, B> where UInt<U, B>: Sub<B1>,
Sub1<UInt<U, B>>: Fact, UInt<U, B> : Mul<<Sub1<UInt<U, B>> as Fact>::F>,
Prod<UInt<U, B>,<Sub1<UInt<U, B>> as Fact>::F>: Unsigned {
type F = Prod<UInt<U, B>,<Sub1<UInt<U, B>> as Fact>::F>;
}
fn main() {
type F0 = <U0 as Fact>::F;
type F1 = <U1 as Fact>::F;
type F2 = <U2 as Fact>::F;
type F3 = <U3 as Fact>::F;
type F4 = <U4 as Fact>::F;
type F5 = <U5 as Fact>::F;
type F20 = <U20 as Fact>::F;
const FACT0: usize = F0::USIZE;
const FACT1: usize = F1::USIZE;
const FACT2: usize = F2::USIZE;
const FACT3: usize = F3::USIZE;
const FACT4: usize = F4::USIZE;
const FACT5: usize = F5::USIZE;
const FACT20: usize = F20::USIZE;
println!("0! = {}", FACT0);
println!("1! = {}", FACT1);
println!("2! = {}", FACT2);
println!("3! = {}", FACT3);
println!("4! = {}", FACT4);
println!("5! = {}", FACT5);
println!("20! = {}\n", FACT20);
println!("Binary structure:");
println!("F4 = {:?}",F4::new());
println!("U24 = {:?}\n",U24::new());
fn print_u24(_: U24) {
println!("type F4 is the same as type U24");
}
print_u24(F4::new());
}
which results in:
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
20! = 2432902008176640000
Binary structure:
F4 = UInt { msb: UInt { msb: UInt { msb: UInt { msb: UInt { msb: UTerm, lsb: B1 }, lsb: B1 }, lsb: B0 }, lsb: B0 }, lsb: B0 }
U24 = UInt { msb: UInt { msb: UInt { msb: UInt { msb: UInt { msb: UTerm, lsb: B1 }, lsb: B1 }, lsb: B0 }, lsb: B0 }, lsb: B0 }
type F4 is the same as type U24
The factorial types F0, F1, F2, F3 F4 F5, F20, are of course generated at compile time.
Constant USIZE associated with trait Unsigned is then used to initialize usize constants, FACT0, FACT1, ...
Well, this is certainly not the most efficient way to compute a factorial at compilation time; const fn is better! However, it is interesting to see that rust typing system is sufficiently powerful to implement some functional and recursive computation at compile time!
This may be useful for other tasks. For example, it is also an interesting alternative to const generics when you have to deal with some arithmetic on it (at least for now). Typically, such typing mechanism are used in generic-array or in nalgebra.
factorial
. Multiplyingn
and1
infactorial(n - 1)
leads to a stackoverflow of the compiler => play.rust-lang.org/… – Anhedral