As @jalf said the map and fold are already in the standard, hidden behind different names:
- map ->
std::transform found in the <algorithm> header - fold ->
std::accumulate , found in the <numeric> header
In Boost.Range, you can find more functional things that are a pretty amazing library. Especially range adapters give a real functional feel, as they create views across other ranges. With C ++ 11, possible predicates are also easy to create on the fly through lambdas.
Boost.Optional may be your "option", depending on what exactly you mean.
Inevitability in C ++ can be achieved by simply declaring your const object. You can avoid copying by passing arguments by reference. In truth, this, of course, is not equivalent to true functional immutability, since immutable containers in functional languages ββcan be copied, but you want, and usually just share the internal representation. After all, copying to recording is awesome if you never write.
On your managed pointers, I had no idea what you mean by them. In C ++, you usually don't need pointers or objects with dynamic allocation. Just create them on the stack: Foo obj; .
If you mean co-ownership, there is std::shared_ptr . There is even a good range adapter there 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 concrete example
my_list.map(f).filter(p).head_opt.get_or_else("not found")
can be implemented as follows (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 using the Clang 3.1 trunk, this leads to the following output:
16 25