How to write C++ like Haskell

http://www.johndcook.com/blog/2016/06/08/computing-higher-moments-with-a-fold/

Here is the C++ version:

#include <iostream>
#include <array>
#include <numeric>
#include <cmath>

int main()
{
  auto sample = {2,30,51,72};
  auto m = std::accumulate(std::begin(sample), std::end(sample), std::array<double, 5>{0, 0, 0, 0, 0},
    [](auto& m, const auto& x) -> decltype(auto)
    {
      ++m[0];
      auto delta = x - m[1];
      auto delta_n = delta / m[0];
      auto delta_n2 = delta_n * delta_n;
      auto t = delta * delta_n * (m[0]-1);
      m[1] += delta_n;
      m[4] += t * delta_n2 * (m[0]*m[0] - 3*m[0] + 3) + 6 * delta_n2 * m[2] - 4 * delta_n * m[3];
      m[3] += t * delta_n * (m[0] - 2) - 3 * delta_n * m[2];
      m[2] += t;
      return m;
    });

  auto mvsk = {m[1], m[2]/(m[0]-1), std::pow(m[0], 0.5)*m[3]/std::pow(m[2], 1.5), m[0]*m[4]/m[2]/m[2] - 3};

  for(auto m : mvsk) std::cout << m << ' ';
  std::cout << std::endl;

  return 0;
}

Unlike the Haskell version, this is not functional, as it uses side-effects: namely, it updates the array in place (ie, “auto& m”). To make it functional, simply remove the ampersand for value-passing semantics.

It’s very interesting that it is possible to write C++ in such an expressive yet compact manner. As the author noted, the OO C++ version is around twice the size, whereas this matches Haskell almost line for line. Technically, the std::accumulate could be written as a simple range-based for loop (also possible in C++), but having a named algorithm on the same order as Haskell’s foldl is much more self-documenting. Also having a self-contained lambda function makes design much more composable in a way that a for loop isn’t. The OO version is probably less readable at first glance too.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s