SICP problem 1.3, it's a very trivial problem usually taught in CS101 first/second week in the uni. The problem states thusly:
Declare a function that takes three numbers as arguments and returns the sum of the squares
of the two larger numbers.
I find it embarrassing that I cannot implement this function:
A non-generic approach would look something like this:
/// Declare a function that takes three numbers as arguments and returns the sum of the squares
/// of the two larger numbers.
fn e3(n1: f32, n2: f32, n3: f32) -> f32 {
match (n1 <= n2, n1 <= n3, n2 <= n1, n2 <= n3) {
(true, true, _, _) => n2 * n2 + n3 * n3,
(_, _, true, true) => n1 * n1 + n3 * n3,
_ => n1 * n1 + n2 * n2,
}
}
#[cfg(test)]
mod test {
#[test]
fn e3() {
assert_eq!(super::e3(2., 1., 3.), 13.);
}
}
easy but it only works if all the parameters happen to be f32
. While writing a generic solution I'm drowning in the rigidity of the type constraints
fn g_e3<T, U, V, R>(n1: T, n2: U, n3: V) -> R
where
T: std::cmp::PartialOrd + std::ops::Mul + std::convert::From<U> + std::convert::From<V>,
U: std::cmp::PartialOrd + std::ops::Mul + std::convert::From<T> + std::convert::From<V>,
V: std::cmp::PartialOrd + std::ops::Mul + std::convert::From<T> + std::convert::From<U>,
<T as std::ops::Mul>::Output: std::ops::Add,
<U as std::ops::Mul>::Output: std::ops::Add,
{
match (
n1 <= n2.into(),
n1 <= n3.into(),
n2 <= n1.into(),
n2 <= n3.into(),
) {
(true, true, _, _) => n2 * n2 + n3 * n3,
(_, _, true, true) => n1 * n1 + n3 * n3,
_ => n1 * n1 + n2 * n2,
}
}
This won't work for obvious reasons. Whenever I fix something, another issue appears. Is there a way to have the compiler automatically deduce the constraints? Like in D:
T4 e3(T1, T2, T3, T4)(const T1 n1, const T2 n2, const T3 n3)
{
return n1 * n1 + n2 * n2 + n3 * n3 - ((n1 <= n2 && n1 <= n3) ? n1 * n1
: (n2 <= n1 && n2 <= n3) ? n2 * n2 : n3 * n3);
}