2012-02-24 32 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描述實質上正是我所要求的,但不會出現與該項目已經得到進一步。

希望這可以幫助別人...

相關問題