12

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...

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
ms-ati
  • 1,297
  • 1
  • 13
  • 17
  • C++ has a garbage collector, by the way. Not part of the standard, though. –  Feb 24 '12 at 23:49
  • 5
    The C++ standard library has functions which are essentially map and fold. They're just called `std::transform` and `std::accumulate`. Boost has an option type. I'm not sure what you mean by "managed pointers" though – jalf Feb 24 '12 at 23:51
  • @jalf I'm looking for something like `my_list.map(f).filter(p).head_opt.get_or_else("not found")`, where my_list is an iterable container of ints, f is a function from int to std::string, p is a predicate which selects a subset of the strings, head_opt returns an option representing the first in the list, and finally get_or_else is the typical function on an Option type which returns the contents of a Some, or the given value for a None – ms-ati Feb 25 '12 at 00:10
  • (in other words, as I wrote, something similar or equivalent to Functional Java...) – ms-ati Feb 25 '12 at 00:13
  • @Vlad Lazarenko: It's more accurate to say that C++ implementations are capable of having a garbage collector, but so far every C++ implementation I've seen do not have such a thing by default. – In silico Feb 25 '12 at 00:25
  • @Insilico: See http://www.hpl.hp.com/personal/Hans_Boehm/gc/ –  Feb 25 '12 at 00:27
  • 1
    @Vlad Lazarenko: Yes, you've proved my point: "C++ implementations are capable of having a garbage collector". But C++ programs typically don't use garbage collectors. – In silico Feb 25 '12 at 00:28
  • @Insilico: Of course they don't. Garbage collector is for pussies :) –  Feb 25 '12 at 00:30
  • 3
    @ms-ati: yes? once again, the standard library has map/fold functions (and I suppose `std::copy_if` is basically `filter`). The syntax is different, but that's what the functions *do* – jalf Feb 25 '12 at 01:02
  • @Jalf perhaps it would have been better to phrase my question "have you used functional transformations of persistent immutable data structures, including Option type, in Scala, Haskell, Functional Java, or similar languages/libraries? If so, do you know of a similar library for C++"? Would that help clarify the question? – ms-tg Feb 27 '12 at 15:03
  • 3
    @ms-tg: Your problem is your use of the word "similar". Because you don't mean "similar"; Xeo gave you something "similar". You mean "exact same semantics." That's different from "similar". You want something that offers functional semantics, not merely functional constructs. – Nicol Bolas Feb 27 '12 at 16:37
  • @NicolBolas Sorry for the confusion! By "similar", I did mean "meets the exact same goals", that is _provides a true functional programming environment on top of the base language_. I just meant that it might have different conventions, names, memory management, etc, from FJ, Scala, Clojure, and the rest. But yes, this question is for the FJ equivalent in the C++ world, which I gather doesn't currently exist. ;) Thanks for your help. – ms-tg Feb 27 '12 at 17:41

3 Answers3

15

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
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • thanks for a complete answer. Unfortunately this is not what I meant. By "option type", I mean the option monad (http://en.wikipedia.org/wiki/Option_type#The_option_monad) as used in Scala, Haskell, Functional Java, and other languages. It exposes the interface of collections monads but contains wither zero elements (None) or 1 element (Some). – ms-tg Feb 27 '12 at 14:56
  • Perhaps it would be more fruitful if you folks answering and voting would consider what I am asking (by trying Functional Java, Scala, Haskell, Clojure, etc) rather than translating an approximation into standard C++ libraries? I know you understand map/reduce as that is what your examples show, but the examples are doing it in an imperative style. It seems that the functional transformations on persistent, immutable, monadic data structures is not something you understand, though...? – ms-tg Feb 27 '12 at 14:59
  • Xeo, I will award you the answer if I don't get a better answer within 1 more day. Thanks again for taking the time to put these examples together. – ms-tg Feb 27 '12 at 15:02
  • 2
    @ms-tg: I'm sorry, but we answer questions to the best of our ability. If you are not satisfied with our answers, then the logical conclusion is that *your question should be improved*, and **not** "everyone who took the time to *try* and answer my question should intead learn 4 new languages, *and then* write me an answer – jalf Feb 27 '12 at 15:07
  • 2
    Finally, apart from that ,I **do** know some functional languages. As you say, I know what map/reduce are, and yes, in my comments I hinted at how to do the same in an imperative style, because as I read the question, that was the best advice I could think of. The bottom line is that **C++ is not a functional language. It can be approximated, and @Xeo has shown *one* such possible approximation. If you want a *different* approximation, then write a better question, which specifies *exactly* what the answer should provide. "Something like this other language/library" is extremely vague. – jalf Feb 27 '12 at 15:08
  • @Jalf, who is **we**? Xeo provided a good attempt to answer, you've provided noise distorting the signal. I understand that you don't like the question and wanted to answer a different one. I'm sorry about that, but I did clearly specify the interface of Functional Java in the question, which again shares these aspects with Scala, etc. – ms-tg Feb 27 '12 at 15:14
  • 1
    @ms-tg: You did specify the interface, and Xeo gave you a pretty good approximation of that interface. No, it's not word-for-word identical. But it's more or less what you asked to be able to do. – Nicol Bolas Feb 27 '12 at 16:29
  • 1
    @ms-tg: As far as I can see, `boost::optional` is exactly what is described in that Wikipedia "Option type" article. It contains either nothing or one value and `get_optional_value_or` is exactly your `get_or_else`. Also, I have to admit that I only looked at functional languages from afar, but what exactly do you mean with "imperative style"? The filling of the `vector`? Please give a specific example. – Xeo Feb 27 '12 at 16:55
  • @Xeo Thanks for your answer. I can't of course explain functional (vs imperative) style in a single comment. Perhaps FJ [Option bind examples](http://functionaljava.org/examples/#Option.bind) will help illustrate what a functional-style option type allows you to do? Again, thanks for your help with this answer. – ms-tg Feb 27 '12 at 17:36
  • @NicolBolas agreed, I will accept this answer as being the closest available today in C++. I hope that someday soon, there will be a library for C++ which _does for C++ what FJ does for Java_ -- as you said below, "provides a full functional programming interface on top of the base language". – ms-tg Feb 27 '12 at 17:37
  • 1
    @ms-tg: [Here](http://ideone.com/2Ctnk)'s a 1:1 translation from the Optional bind example to C++. Note that I needed to write the "`bind`"(bad name, `apply` would be better) and print function myself, since `boost::optional` doesn't provide those out of the box. However, I don't even need to specify what exactly I want to print. :P Note that you could theoretically "range-ify" the `boost::optional` and just use the Boost.Range adaptors on a 1 element range, which saves you from writing `transform`/`filter`/etc yourself. – Xeo Feb 27 '12 at 18:13
  • @ms-tg: Btw, what's the difference between "Optional bind" and "Optional map" in that reference? It seems to me that both functions serve the same purpose (i.e., pass the contained value (if any) to the provided function, and return its result), but I may be misunderstanding something. – Xeo Feb 27 '12 at 18:24
  • @Xeo **short**: well, the function passed to "bind" returns an Option, but the function passed to "map" returns a value of the contained type. **long**: see [map](http://en.wikipedia.org/wiki/Map_%28higher-order_function%29) and [bind](http://en.wikipedia.org/wiki/Monad_%28functional_programming%29) – ms-tg Feb 27 '12 at 18:35
  • @ms-tg: Ah, ok, that's all I wanted to know. In that case, the Option bind example could've been rewritten as `Option<...> p1 = some(o1.map(...));` if I've understood that correctly? If yes, then I don't really see the need to make that an extra function, but oh-well. – Xeo Feb 27 '12 at 18:38
  • @Xeo, no that's not right, `o1.map(func1)` returns `some(func1(v))`, or `none` if o1 was a None. You would more likely go the other way, and implement `map` in terms of `bind`. – ms-tg Feb 27 '12 at 18:43
  • @ms-tg: Ah, yeah, I misread your comment, sorry for that. Now, in that case, there's no need for the two functions in C++, because `boost::optional` is implicitly constructible from the contained type, so you would just return that. – Xeo Feb 27 '12 at 18:46
  • @Xeo Yes, but then you'd miss the _entire_ point of the functional-style chained monadic transformations... ;) – ms-tg Feb 27 '12 at 19:05
  • 1
    @ms-tg: Given that I don't really understand what monads are, that's very possible. :) – Xeo Feb 27 '12 at 20:01
2

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I think you misunderstand what an immutable data structure is. They are generally able to keep their history. For instance, adding a node to an immutable red/black tree would only update log(n) nodes, and any reference to the old tree would make that invisible. – Joel Feb 25 '12 at 01:00
  • 1
    @Joel: Err... *adding* to an *immutable* tree? That sounds so wrong, I think you should clarify... Also, there is no "updating" when something is *not changeable at all*, aka exactly what immutability means. – Xeo Feb 25 '12 at 01:34
  • 1
    Calling an add function from an immutable tree. I felt that to be somewhat pedantic, so didn't spell it out. Just as Java has a + operator on their _immutable_ strings. The point is that although a new tree appears to be returned, in reality that's rarely the case. Most of the tree is reused. – Joel Feb 25 '12 at 01:46
  • @Xeo Please see this link for an explanation of persistant immutable data structures in Scala -- it's a common feature in functional languages: http://stackoverflow.com/questions/3107151/persistent-data-structures-in-scala – ms-tg Feb 27 '12 at 14:53
  • @NicolBolas Thank you! If "doesn't exist" is the correct answer, then that's the answer we want to get to. Of course, Java was not a functional language either, but after many attempts (including Guava, etc), Functional Java has filled that hole very well in the Java world. If no such library exists for C++, at the present time, then that is the answer I'm looking for! Again, thanks. – ms-tg Feb 27 '12 at 17:32
1

FC++ appears to be an older library (2001-era, last modified in 2007 on SourceForge) offering some functional programming features in C++.

Hmmm, FC++ was submitted as a potential Boost library in 2003?

Elsewhere on StackOverflow, the primary original developer of FC++ indicated that modern C++ and Boost have superceded some of FC++'s use cases, but that others are still not available in a modern C++ library?

It also appears that someone got as far as writing a README for a github project that describes essentially exactly what I was asking for, but doesn't appear to have gotten any further with the project.

Hope this helps someone...

Community
  • 1
  • 1
ms-tg
  • 2,688
  • 23
  • 18