ExamplesBy LevelBy TopicLearning Paths
274 Intermediate

274: Numeric Reductions: sum() and product()

Functional Programming

Tutorial

The Problem

Summing or multiplying all elements of a collection is one of the most fundamental computational operations — from computing totals in spreadsheets to calculating factorials in mathematics, to aggregating metrics in monitoring systems. While these could be implemented with fold(), Rust provides sum() and product() as first-class methods that express intent clearly and can be implemented efficiently by the type system via the Sum and Product traits.

🎯 Learning Outcomes

  • • Understand sum() and product() as ergonomic specializations of fold for numeric types
  • • Recognize that sum() returns zero and product() returns one for empty iterators (identity elements)
  • • Use sum() and product() on iterators of references by using .copied() or .cloned()
  • • Implement the Sum and Product traits for custom numeric types
  • Code Example

    #![allow(clippy::all)]
    //! 274. Numeric reductions: sum() and product()
    //!
    //! `sum()` and `product()` fold iterators of numbers with + and * respectively.
    
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_sum_gauss() {
            let sum: i32 = (1..=100).sum();
            assert_eq!(sum, 5050);
        }
    
        #[test]
        fn test_product_factorial() {
            let fact5: u64 = (1u64..=5).product();
            assert_eq!(fact5, 120);
        }
    
        #[test]
        fn test_sum_empty() {
            let s: i32 = Vec::<i32>::new().into_iter().sum();
            assert_eq!(s, 0);
        }
    
        #[test]
        fn test_product_empty() {
            let p: i32 = Vec::<i32>::new().into_iter().product();
            assert_eq!(p, 1); // identity element
        }
    }

    Key Differences

  • Trait-based: Rust's sum()/product() are generic over any type implementing Sum/Product; OCaml requires type-specific fold expressions.
  • Identity elements: Both use the mathematical identity — zero for sum, one for product — on empty iterators.
  • Overflow behavior: Rust's sum()/product() wrap on integer overflow in release mode; use checked_sum patterns or saturating arithmetic when needed.
  • Custom types: Implementing std::iter::Sum for a custom type lets it participate in sum() chains naturally.
  • OCaml Approach

    OCaml uses List.fold_left (+) 0 for sum and List.fold_left ( *) 1 for product — there are no dedicated functions:

    let sum xs = List.fold_left (+) 0 xs
    let product xs = List.fold_left ( * ) 1 xs
    let () = assert (sum [1;2;3;4;5] = 15)
    

    Base.List.sum and Base.List.product exist in Jane Street's Base library.

    Full Source

    #![allow(clippy::all)]
    //! 274. Numeric reductions: sum() and product()
    //!
    //! `sum()` and `product()` fold iterators of numbers with + and * respectively.
    
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_sum_gauss() {
            let sum: i32 = (1..=100).sum();
            assert_eq!(sum, 5050);
        }
    
        #[test]
        fn test_product_factorial() {
            let fact5: u64 = (1u64..=5).product();
            assert_eq!(fact5, 120);
        }
    
        #[test]
        fn test_sum_empty() {
            let s: i32 = Vec::<i32>::new().into_iter().sum();
            assert_eq!(s, 0);
        }
    
        #[test]
        fn test_product_empty() {
            let p: i32 = Vec::<i32>::new().into_iter().product();
            assert_eq!(p, 1); // identity element
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        #[test]
        fn test_sum_gauss() {
            let sum: i32 = (1..=100).sum();
            assert_eq!(sum, 5050);
        }
    
        #[test]
        fn test_product_factorial() {
            let fact5: u64 = (1u64..=5).product();
            assert_eq!(fact5, 120);
        }
    
        #[test]
        fn test_sum_empty() {
            let s: i32 = Vec::<i32>::new().into_iter().sum();
            assert_eq!(s, 0);
        }
    
        #[test]
        fn test_product_empty() {
            let p: i32 = Vec::<i32>::new().into_iter().product();
            assert_eq!(p, 1); // identity element
        }
    }

    Exercises

  • Compute the sum of squares of a range using map(|x| x*x).sum::<i64>().
  • Implement a product function for floating-point numbers that handles the case of any zero element by returning zero early.
  • Use sum() and count() together to compute the arithmetic mean of a Vec<f64>.
  • Open Source Repos