Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 空范围折叠操作的结果_C++_Functional Programming - Fatal编程技术网

C++ 空范围折叠操作的结果

C++ 空范围折叠操作的结果,c++,functional-programming,C++,Functional Programming,我正在写一个允许对范围进行一些函数编程操作的程序。范围是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 impleme

我正在写一个允许对范围进行一些函数编程操作的程序。范围是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? 
auto r=范围(4);//惰性数值范围{0,1,2,3}
自动r0=范围(0);//空范围{}
向量vs{“a”,“bb”};
向量vs0{};
//这是显而易见的,也是实现的一部分
cout我假设您的“文件夹”是某个模板的实例,附带了一个二进制函数,可能还有一个初始值

传统上,fold被定义为递归地调用所述的二进制函数(initial,first),然后(old value,next),直到调用它的资源用完为止

没有这样的初始值,减法和除法的工作方式与您期望的相同(例如fold({1,2})是1/2)

因此,减法和除法的“文件夹”要么是“逆之和”和“逆之积”(即,fold(r)=1/fold(r),fold(r)=fold(r),这似乎很无聊),要么是根本不同的东西,在空容器上不起作用

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

通过“不工作”,他们可以抛出异常,或者返回类似于
boost::optional
——即在空列表中,他们不返回任何内容

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

编辑:根据下面的评论,对答案进行了改进

这里真正的诀窍是减法和除法没有左手恒等式,但有右手恒等式

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

也就是说,用二进制操作的标识表示列表
{a,b,c}
上的折叠的自然方式是:

( (id *op* a) *op* b ) *op c
但对于没有左手标识的操作,这不起作用

但是,如果您反转折叠用手,则会得到以下结果:

a *op* (b *op* (c *op* id))
只要你有右手的身份就行

这对于
div
sub
非常重要--
div
的右侧标识为1,
sub
的右侧标识为0,但两者都没有左侧标识。(对于所有
x
,不存在
e-x=x
的元素
e
。对于所有
x
,存在
e
的元素
x-e=x
,即0)

求幂也是如此(它的右手标识为
1
,但没有左手标识)


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

通常,
fold
函数由3个参数定义:要折叠的列表、要应用的函数和累加器的起始值。折叠空列表的返回值自然就是作为参数给出的起始值。另外,我只想说,我认为重载
|
作为折叠运算符是个坏主意。我知道
std::acculate
以及如何指定初始值。我的问题是,对于某些ops,这个值应该是多少。项目的目标不是让每个人都满意。它只适合于一些小范围的用户(C++OneLiner、Codejam等)。我是否可以建议为此实现命名中缀操作符,而不是以可能令人困惑的方式覆盖其他操作符?即,
myVec*fold*sum
风格语法,而不是
myVec | | sum
。(是的,这涉及到以奇怪的方式重写运算符,但不太容易混淆)@Reuben
template-struct-NamedOperator{BinOp-op;}template-struct-LeftForm{BinOp-op;tlhs;LeftForm(ta,BinOp-b):op(b),lhs(a){};模板LeftForm操作符*(T left,NamedOperator nop){返回LeftForm(left,nop.op);}模板自动操作符*(LeftForm left,U rhs)->decltype(left.op(left.lhs,rhs)){返回left.op(left.lhs,rhs);}
容易吗?更难的是使语法干净地生成
+sum+
&
*mul*
等运算符。代码是半speudo-Code。您的假设是正确的-文件夹是带有trait方法的模板函子fold\u init\u value()。在将折叠的定义(在我的头脑中)从
R0+R1+R2…
替换为
init+R0+R1…
之后,对于
div
sub
(1和0)的空范围,应该是什么值变得很清楚。谢谢。@leonid注意到这使得div和sub很无聊。它们只是以可分离的方式与add和mult不同(即,对序列应用统一的每元素变换,然后add或mult,得到相同的结果)。当错误发生时,你需要一种方法来传播它们,所以你可能想制定一种机制?我不明白-
无聊
可分离方式
。这是抽象代数吗?不幸的是,我不知道。顺便说一句,我找到了答案--@LeonidVolnitsky--“无聊”就像“不有趣”一样。“可分离”--对N个输入的操作相对于第二个操作而言是“可分离的”,前提是它可以表示为对N个输入中的每个输入的一元操作,然后是第二个操作。请注意,
div
sub
都没有左侧标识元素——没有元素
e
,因此
e-x=x
适用于所有
x
,同样适用于
e/x=x
。同时,存在一个元素
e
,使得
e+x=x
适用于所有