空范围折叠操作的结果

时间:2012-12-12 18:38:54

标签: c++ functional-programming

我正在编写library,它允许对范围进行一些函数编程操作。范围是STL容器的概括。我的问题是,对于空范围的折叠应该是什么结果?

auto r  = range(4);    // lazy numeric range {0,1,2,3}
auto r0 = range(0);    // empty range {}
vector<string> vs  {"a", "bb"};
vector<string> vs0 {};

// this is obvious and implemented part    

cout <<  (r  || add);  // 6,  || - folding op
cout <<  (r0 || add);  // 0
cout <<  (vs || add);  // "abb"
cout <<  (vs0|| add);  // ""

cout <<  (r  || mul);  // 0
cout <<  (r0 || mul);  // 1

cout <<  (r  || max);  // 3

//  What result of these should be?

cout <<  (r0 || div);   // ???
cout <<  (r0 || sub);   // ???
cout <<  (r0 || max);   // -∞ ???
cout <<  (r0 || min);   // +∞ ???
cout <<  (r0 || ???);   // result of arbitrary op? 

编辑 - 答案

http://en.wikipedia.org/wiki/Identity_element

1 个答案:

答案 0 :(得分:2)

我假设您的“文件夹”是某个模板的实例,附加了二进制函数,可能是初始值。

传统上,fold被定义为递归调用所述二进制函数(初始,第一个),然后(旧值,下一个),直到你没有东西来调用它。

没有这样的初始值,这样减法和除法就像你期望的那样工作(使得fold({1,2})为1/2)。

因此,减法和除法的“文件夹”是“逆的和”和“逆的乘积”(即,fold(r)= 1 / fold(r),fold(r)= -fold(r) ,这似乎很无聊),或者它们是根本不同的东西,不适用于空容器。

max和min应该清楚地生成给定类型的最高值和最低值,或者是在空容器上没有意义的第二种类型的文件夹。

通过“不工作”,他们可以抛出异常,或者他们可以返回类似boost::optional<T>的东西 - 即,在空列表中,它们不会返回任何内容。

您的文件夹类型可以使用一个函数来查找给定类型的初始值,该函数应解析为特征模板类或自由函数(类似于std::begin)。

...

编辑:从下面的评论中,对答案进行了改进。

这里的真正诀窍是减法和除法没有左手身份但是有一个右手身份!

只有右手身份的操作应表示为右手折叠,只有左手身份的操作应表示为左手折叠(aka,foldr和foldl)

即,使用二进制操作{a,b,c}的标识id在列表*op*上表示折叠的自然方式是:

( (id *op* a) *op* b ) *op c

但是对于没有左手身份的操作,这不起作用。

然而,如果你扭转了褶皱的手性,你会得到这个:

a *op* (b *op* (c *op* id))

只要你有一个右手身份就行。

这对于divsub非常重要 - div的右手标识为1,而sub的右手标识为0,但既没有左手身份。 (没有元素e,所有e-x = x都有x。有一个元素e,所有x-e = xx,即0)。

取幂也是如此(它具有1的右手身份,但没有左手身份。

这仍然不符合fold div应该做什么的天真期望。它适用于长度为2的列表,但是在长度为3的列表上会发生不直观的事情。但至少它在数学上是合理的。 :)