我正在写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

最佳答案

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

传统上,折叠被定义为(首先,首先)递归地调用所述二进制函数,然后是(旧值,其次)递归调用该二进制函数,直到用尽所有东西来对其进行调用。

没有这样的初始值,以致于减法和除法以您期望的方式工作(例如fold({1,2})为1/2)。

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

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

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

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

...

编辑:从下面的评论,答案的改进。

真正的窍门是,没有左撇子身份可以进行减法和除法运算,但是有右撇子身份!

仅具有右手身份的操作应表示为右手折叠,而仅具有左手身份的操作应表示为左手折叠(aka,folder和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 = x都具有x,即0)。

求幂也是如此(它的右手身份为1,但没有左手身份)。

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

关于c++ - 空范围折叠操作的结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13846386/

10-10 11:24