What a fascinating concept! Let's create a novel way to represent numbers using these primitives. I propose we call them "Multis" (short for Multiplicative Units).
We'll define two traits for our Multis: Base
and Value
. The Base
trait will dictate how many times the Value
should be multiplied, and the Value
trait will hold the actual count.
pub trait Base: std::fmt::Debug {
type Value;
}
pub trait Value: std::fmt::Debug {
fn multiply(self, base: &dyn Base) -> usize;
}
Now, let's create some concrete implementations for our Multis. For example, a Single
Multi that has no multiplier (base of 1) but still needs a value:
#[derive(Debug)]
struct Single<T>(T);
impl<T> Value for Single<T>
where
T: Value + std::fmt::Debug,
{
fn multiply(self, _base: &dyn Base) -> usize {
self.0.multiply(_base)
}
}
impl<T: Debug> Base for Single<T> {
type Value = T;
}
And another example, a Repeat
Multi that repeats its value by a given multiplier (base):
#[derive(Debug)]
struct Repeat<T>(T, usize);
impl<T> Value for Repeat<T>
where
T: Value + std::fmt::Debug,
{
fn multiply(self, base: &dyn Base) -> usize {
self.0.multiply(base).saturating_mul(base.value())
}
}
impl<T: Debug> Base for Repeat<T> {
type Value = usize;
}
In the Repeat
Multi, we use Rust's built-in saturating multiplication to avoid overflowing when multiplying the value by the base.
Now that we have our Multis, let's create a Composite
Multi that can be constructed from other Multis. This will allow us to build up more complex numbers in a compositional manner:
#[derive(Debug)]
struct Composite<T>(Vec<Box<dyn Base + Value>>);
impl<T> Composite<T>
where
T: 'static,
{
fn new(multis: Vec<Box<dyn Base + Value>>) -> Self {
Composite(multis)
}
}
impl<T> Value for Composite<T>
where
T: 'static,
{
fn multiply(self, base: &dyn Base) -> usize {
self.0.iter()
.map(|multi| multi.multiply(base))
.sum::<usize>()
}
}
Finally, let's define a Number
type that can be constructed from our Multis and provide an implementation for the Display
trait to make debugging easier:
#[derive(Debug)]
struct Number<T>(Composite<T>);
impl<T> Display for Number<T>
where
T: 'static + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "({:?})", self.0)
}
}
With these building blocks, you can create a wide variety of numbers using our compositional system:
fn main() {
let single1 = Single(2);
let repeat5 = Repeat(single1, 3); // 2 * 3 = 6
let composite = Composite::new(vec![Box::new(repeat5), Box::new(single1)]);
println!("{}", Number(composite)); // (6, 2)
}
In this example, we create a Repeat
Multi that repeats the value of Single(2)
three times, and then combine it with another instance of Single(2)
in a Composite
. The resulting number is (6, 2)
, which can be interpreted as 6 + 2.
This system ensures reusability of primitives by not allowing duplication and takes full advantage of the compositional aspect. You can create complex numbers from simple ones, leveraging the properties of the base and value to build up your desired representation.
I hope this implementation aligns with your vision! If you'd like any modifications or have further questions, please let me know. 😊