Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C++ library similar/equivalent to Functional Java?

Are there open source C++ libraries that are similar or equivalent to the excellent Functional Java library?

Specific features would include:

  • map, fold/reduce, filter, etc on iterables or the like
  • option type
  • immutable data-structure implementations

(asked out of curiosity, having been away from C++ for some years)

Yes, some of these features have traditionally been thought to require garbage collection. But with modern C++ features and libraries, has anyone started passing managed pointers through the functional transformations or something?

UPDATE To be clear, I'm wondering the there's something similar to Functional Java, so that the following might be typical syntax:

// assumptions:
//   * my_list is a standard library iterable of ints
//   * f is a function of int that returns a std::string
//   * p is a predicate of std::string returning bool
//   * head_opt returns an option type
stream(my_list).map(f).filter(p).head_opt.get_or_else("None")

This is the idiom that Functional Java offers, and believe me it's really easy to get accustomed to it...

like image 265
ms-ati Avatar asked Feb 24 '12 23:02

ms-ati


2 Answers

As @jalf said, map and fold are already in the standard, hidden behind different names:

  • map -> std::transform, found in header <algorithm>
  • fold -> std::accumulate, found in header <numeric>

Many more functional stuff can be found in Boost.Range, which is a pretty awesome library. Especially the range adaptors give a real functional feeling, as they create views over other ranges. With C++11, possible predicates are also easily created on-the-fly through lambdas.

Boost.Optional might be your "option type", depending on what exactly you mean with that.

Immutability in C++ can be achieved by simply declaring your object const. You can avoid copies using by-reference argument passing. Truth be told, this is of course no real equivalent to true functional immutability, since immutable containers in functional languages can be copied however your want and usually just share the internal representation. After all, copy-on-write is awesome if you never write.

On your managed pointers, I got no idea what you mean by them. In C++, you usually don't need pointers or dynamically allocated objects at all. Just create them "on the stack": Foo obj;.

If you mean shared ownership, there's std::shared_ptr. There even is a nice range adaptor if you store such a pointer in a container:

#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/algorithm/generate.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <vector>
#include <memory>
#include <algorithm>
#include <iterator>
#include <iostream>

int main(){
  std::vector<std::shared_ptr<int>> v(5);
  int i = 0;
  boost::generate(v, [&i]{ return std::make_shared<int>(i++); });
  boost::copy(v | boost::adaptors::indirected,
      std::ostream_iterator<int>(std::cout));
}

Your specific example

my_list.map(f).filter(p).head_opt.get_or_else("not found")

might be implemented like this (note that std::vector is the default container in C++):

// Warning, C++11 only!
// Boost.Range doesn't like lambdas without this:
#define BOOST_RESULT_OF_USE_DECLTYPE

#include <vector>
#include <string>
#include <iterator>
#include <iostream>
#include <boost/optional.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/generate.hpp> // only needed for filling the vector
#include <boost/range/algorithm/copy.hpp> // only needed for printing

// we need a little helper for the optional stuff
struct head_opt_gen{} head_opt; // just a tag type

template<class Range>
auto operator|(Range const& r, head_opt_gen)
  -> boost::optional<decltype(r.front())>
{
  if(r.empty())
    return boost::none;
  return r.front();
}

int main(){
  using namespace boost::adaptors;
  std::vector<int> v(5);
  int i = 0;
  boost::generate(v, [&]()->int{ ++i; return i*i; });
  // first, without the optional stuff
  boost::copy(v | transformed([](int x){ return std::to_string(x); })
                | filtered([](std::string const& s){ return s.size() > 1; }),
      std::ostream_iterator<std::string>(std::cout, "\n"));
  std::cout << "=====================\n";
  // now with
  std::cout << boost::get_optional_value_or(
      v | transformed([](int x){ return std::to_string(x); })
        | filtered([](std::string const& s){ return s.size() > 2; }) // note: > 2
        | head_opt, "none");
}

Compiled with Clang 3.1 Trunk, this results in the following output:

16
25
=====================
none
like image 153
Xeo Avatar answered Nov 15 '22 19:11

Xeo


I don't think there are any libraries that explicitly feature immutable data structures. Though nobody's stopping you from simply not changing data structures outside of certain contexts.

But you can build some of what you want out of Boost.Range. It has powerful range-based constructs, filtering, and so forth. You'll have to deal with the memory management yourself, though.


Your question seems to be, "Is there a library in C++ that exactly implements the behavior of strict functional programming constructs?" The answer is no. To my knowledge, there is no C++ library that has as its fundamental purpose to explicitly and directly implement strict functional programming constructs. C++ is ultimately not a functional language.

There are many approximations of various functional constructs. But there is no library that implements them exactly according to the rules of strict functional programming.

like image 42
Nicol Bolas Avatar answered Nov 15 '22 19:11

Nicol Bolas