2012-02-24 92 views
4

是否存在与优秀的Functional Java library类似或相当的开源C++库?是否有与C++类似的功能Java库?

具体功能将包括:

  • 地图,折叠/减少,滤波器等上iterables或类似物
  • 选项类型
  • 不可变的数据结构实现

(出于好奇心,已经离开C++一些年)

是的,其中一些功能传统上被认为需要垃圾收集。但是通过现代C++特性和库,有没有人开始通过功能转换来传递托管指针?

UPDATE 要清楚,我想知道的有类似功能的Java的东西,所以,下面可能是典型的语法:

// 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") 

这是习惯用法,功能Java提供,并相信我它真的很容易习惯它...

+0

顺便说一下,C++有一个垃圾收集器。不过,不是标准的一部分。 – 2012-02-24 23:49:24

+5

C++标准库具有基本上是地图和折叠的功能。他们只是被称为'std :: transform'和'std :: accumulate'。 Boost有一个选项类型。我不确定你的意思是“托管指针”虽然 – jalf 2012-02-24 23:51:58

+0

@jalf我正在寻找像'my_list.map(f).filter(p).head_opt.get_or_else(“not found”)',其中my_list是一个int的可迭代容器,f是一个从int到std :: string的函数,p是一个用于选择字符串子集的谓词,head_opt返回表示列表中第一个的选项,最后get_or_else是典型的函数on一个Option类型,它返回一个Some的内容,或一个None的给定值 – 2012-02-25 00:10:11

回答

8

正如@jalf说,地图和折叠已经在标准中,隐藏不同的名字后面:

  • 地图 - >std::transform,在标头中找到<algorithm>
  • 倍 - >std::accumulate,在报头<numeric>发现

许多更多功能的东西可以在Boost.Range,这是一个非常棒的图书馆。尤其是range adaptors给人一种真实的功能感,因为他们在其他范围内创建了视图。通过C++ 11,可以通过lambdas轻松创建可能的谓词。

Boost.Optional可能是您的“选项类型”,具体取决于您的意思。

C++中的不变性可以通过简单地声明对象const来实现。您可以避免使用通过参考参数传递的副本。真相被告知,这当然不等于真正的功能不可变性,因为函数式语言中的不可变容器可以被复制,但是你想要的并且通常只是共享内部表示。毕竟,如果你从不写,写入时拷贝是非常棒的。

在你的托管指针上,我不知道你是什么意思。在C++中,通常根本不需要指针或动态分配的对象。只需创建它们“堆叠”:Foo obj;

如果您的意思是共享所有权,那么有std::shared_ptr。甚至有一个很好的范围适配器,如果你存储这种指针的容器:

#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)); 
} 

你的具体例子

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

可能是这样的(注实现即std::vector是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"); 
} 

与锵3.1中继线编译,这导致下面的输出:

16 
25 
===================== 
none 
+0

感谢您的完整答案。不幸的是,这不是我的意思。通过“选项类型”,我指的是在Scala,Haskell,Functional Java和其他语言中使用的选项monad(http://en.wikipedia.org/wiki/Option_type#The_option_monad)。它暴露了集合monad的接口,但包含了枯萎零元素(无)或1个元素(某些)。 – 2012-02-27 14:56:40

+0

如果你回答和投票会考虑我想问的问题(通过尝试Functional Java,Scala,Haskell,Clojure等),而不是将近似转换成标准C++库,那么它可能会更有成效吗?我知道你理解map/reduce就像你的例子所显示的那样,但是这些例子是以一种强制性的方式来做的。看起来,对于持久的,不可改变的一元数据结构的功能转换并不是你理解的,尽管......? – 2012-02-27 14:59:28

+0

Xeo,如果我在1天内没有得到更好的答案,我会给你答案。再次感谢您花时间把这些例子放在一起。 – 2012-02-27 15:02:00

2

我不认为有任何库明确拥有不可变的数据结构。尽管没有人阻止你在某些情况之外不改变数据结构。

但是你可以建立一些你想要的Boost.Range。它具有强大的基于范围的构造,过滤等等。不过,你必须自己处理内存管理。


你的问题似乎是,“有没有在C++库恰好实现了严格的函数编程结构的行为?”答案是不。据我所知,没有C++库的基本目的是明确而直接地实现严格的函数式编程结构。 C++最终不是一种功能性语言。

各种功能构建体有许多近似值。但没有一个库完全按照严格的函数式编程规则来实现它们。

+0

我想你会误解一个不可变的数据结构。他们通常能够保持自己的历史。例如,向不可变的红/黑树添加节点只会更新log(n)节点,并且对旧树的任何引用都会使其不可见。 – Joel 2012-02-25 01:00:52

+1

@Joel:Err ... *将*添加到*不可变的树中?这听起来很错误,我认为你应该澄清......而且,当某些东西*根本不可改变时,没有“更新”,也就是说不可变性意味着什么。 – Xeo 2012-02-25 01:34:40

+1

从不可变树调用添加函数。我觉得有些迂腐,所以没有说出来。就像Java在其_immutable_字符串上有+运算符一样。问题是,尽管似乎还有一棵新树,但实际情况很少如此。大部分树被重用。 – Joel 2012-02-25 01:46:22

1

FC++似乎是一个较旧的库(2001时代,last modified in 2007 on SourceForge在c)中提供一些功能编程特性++。

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

其他地方在计算器上,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?

还可以看出一个人得到尽可能写README for a github project描述实质上正是我所要求的,但不会出现与该项目已经得到进一步。

希望这可以帮助别人...

相关问题