views:

188

answers:

2

The FC++ library provides an interesting approach to supporting functional programming concepts in C++.

A short example from the FAQ:

take (5, map (odd, enumFrom(1)))

FC++ seems to take a lot of inspiration from Haskell, to the extent of reusing many function names from the Haskell prelude.

I've seen a recent article about it, and it's been briefly mentioned in some answers on stackoverflow, but I can't find any usage of it out in the wild.

Are there any open source projects actively using FC++? Or any history of projects which used it in the past? Or does anyone have personal experience with it?

There's a Customers section on the web site, but the only active link is to another library by the same authors (LC++).

As background: I'm looking to write low latency audio plugins using existing C++ APIs, and I'm looking for tooling which allows me to write concise code in a functional style. For this project I wan't to use a C++ library rather than using a separate language, to avoid introducing FFI bindings (because of the complexity) or garbage collection (to keep the upper bound on latency in the sub-millisecond range).

I'm aware that the STL and Boost libraries already provide support from many FP concepts--this may well be a more practical approach. I'm also aware of other promising approaches for code generation of audio DSP code from functional languages, such as the FAUST project or the Haskell synthesizer package.

+7  A: 

This isn't an answer to your question proper, but my experience with embedding of functional style into imperative languages has been horrid. While the code can be almost as concise, it retains the complexity of reasoning found in imperative languages.

The complexity of the embedding usually requires the most intimate knowledge of the details and corner cases of the language. This greatly increases the cost of abstraction, as these things must always be taken into careful consideration. And with a cost of abstraction so high, it is easier just to put a side-effectful function in a lazy stream generator and then die of subtle bugs.

An example from FC++:

struct Insert : public CFunType<int,List<int>,List<int> > {
   List<int> operator()( int x, const List<int>& l ) const {
      if( null(l) || (x > head(l)) )
         return cons( x, l );
      else
         return cons( head(l), curry2(Insert(),x,tail(l)) );
   }
};

struct Isort : public CFunType<List<int>,List<int> > {
   List<int> operator()( const List<int>& l ) const {
      return foldr( Insert(), List<int>(), l );
   }
};

I believe this is trying to express the following Haskell code:

-- transliterated, and generalized
insert :: (Ord a) => a -> [a] -> [a]
insert x [] = [x]
insert x (a:as) | x > a = x:a:as
                | otherwise = a:insert x as

isort :: (Ord a) => [a] -> [a]
isort = foldr insert []

I will leave you to judge the complexity of the approach as your program grows.

I consider code generation a much more attractive approach. You can restrict yourself to a miniscule subset of your target language, making it easy to port to a different target language. The cost of abstraction in a honest functional language is nearly zero, since, after all, they were designed for that (just as abstracting over imperative code in an imperative language is fairly cheap).

luqui
"just as abstracting over imperative code in an imperative language is fairly cheap" Not always; look at Java. The abstraction features in functional languages are equally useful for imperative code. Lacking those features isn't a "paradigm", it's just a design defect.
keegan
Thanks, that's really useful--I'll try the code-gen approach first. Having say an EDSL in Haskell to generate low level time-sensitive code would be ideal. Plus there lots of existing open source projects for DSP and realtime embedded software which take a similar approach, including FAUST, Feldspar, and Haskell Synthesizer, and Atom.
mattbh
+2  A: 

I'm the primary original developer of FC++, but I haven't worked on it in more than six years. I have not kept up with C++/boost much in that time, so I don't know how FC++ compares now. The new C++ standard (and implementations like VC++) has a bit of stuff like lambda and type inference help that makes some of what is in there moot. Nevertheless, there might be useful bits still, like the lazy list types and the Haskell-like (and similarly named) combinators. So I guess try it and see.

(Since you mentioned real-time, I should mention that the lists use reference counting, so if you 'discard' a long list there may be a non-trivial wait in the destructor as all the cells' ref-counts go to zero. I think typically in streaming scenarios with infinite streams/lists this is a non-issue, since you're typically just tailing into the stream and only deallocating things one node at a time as you stream.)

Brian
Thanks for the info. It's really useful to know what sort of approach will keep destructor times low, since that was my main reason for considering C++. FC++ is really interesting work!
mattbh