map/fold运算符(在c++中)
map/fold operators (in c++)
我正在编写一个库,它可以对范围进行映射/折叠操作。我需要和操作员一起做这些。我对功能编程不是很熟悉,我暂时选择了*
作为map,||
作为fold。因此,在区间8 < x < 9
:中找到cos(x)
的最大值(蛮力算法)
double maximum = ro::range(8, 9, 0.01) * std::cos || std::max;
在上述内容中,ro::range
可以替换为任何STL容器。
如果地图/折叠操作符有任何约定,我不想与众不同。我的问题是:有数学符号吗?或者有任何语言使用运算符来表示映射/折叠吗?
**编辑**
对于那些提问的人,下面是RO目前可以做什么的小演示。scc
是一个可以评估C++片段的小实用程序。
// Can print ranges, container, tuples, etc directly (vint is vector<int>) :
scc 'vint V{1,2,3}; V'
{1,2,3}
// Classic pipe. Alogorithms are from std::
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}
// Assign 42 to [2..5)
scc 'vint V=range(0,9); range(V/2, V/5) = 42; V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}
// concatenate vector of strings ('add' is shotcut for std::plus<T>()):
scc 'vstr V{"aaa", "bb", "cccc"}; V || add'
aaabbcccc
// Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"}; V * size || (_1+_2)'
9
// Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99]; range(s) = "abc"; (range(s) << "XYZ") - "bc"'
aXYZ
// Remove non alpha-num characters and convert to upper case
scc '(range("abc-123, xyz/") | isalnum) * toupper'
ABC123XYZ
// Hide phone number:
scc "str S="John Q Public (650)1234567"; S|isdigit='X'; S"
John Q Public (XXX)XXXXXXX
这实际上更像是一个注释,而不是一个真实的答案,但它太长了,无法放入注释中。
至少如果我对这个术语的记忆正确的话,map本质上是std::transform
,fold是std::accumulate
。假设这是正确的,我认为尝试自己写最多也是不明智的。
如果你想使用映射/折叠样式的语义,你可以这样做:
std::transform(std::begin(sto), std::end(sto), ::cos);
double maximum = *std::max_element(std::begin(sto), std::end(sto));
虽然std::accumulate
更像是一个通用折叠,但std::max_element
基本上是一个fold(..., max);
。如果您喜欢单个操作,可以执行以下操作:
double maximum = *(std::max_element(std::begin(sto), std::end(sto),
[](double a, double b) { return cos(a) < cos(b); });
为此,我敦促你们重新考虑超载运营商。我上面给出的任何一个例子对任何一个合理的C++程序员来说都应该是清楚的。你所举的例子对大多数人来说是完全不透明的。
在更普遍的层面上,我敦促操作员在超载时格外小心。运算符重载在正确使用时非常好——能够为任意精度整数、矩阵、复数等重载运算符,使使用这些类型的代码比没有重载运算符的代码更可读、更容易理解。
不幸的是,当你以意想不到的方式使用运算符时,恰恰相反——这些用法肯定是非常意想不到的——事实上,完全属于"非常令人惊讶"的范围。如果这些运算符在特定领域得到了很好的理解,但与C++中的其他用途相反,可能会有问题(但至少有一点理由)。然而,在这种情况下,你似乎在发明一种"无中生有"的符号——我不知道有人使用任何运算符C++支持重载来表示折叠或映射(也没有任何视觉上相似或类似的东西)。简而言之,以这种方式使用重载是一个糟糕且不合理的想法。
在我所知道的语言中,没有标准的折叠方法。Scala使用运算符/:
和:
以及方法名称,Lisp有reduce
,Haskell有foldl
。
另一方面,在我所知道的所有语言中,map
更常见,简称为map
。
下面是fold
在准人类可读中缀C++语法中的实现。请注意,该代码不是很健壮,只是用来证明这一点。它支持更常见的3参数fold
运算符(范围、二进制运算和中性元素)。
这很容易成为虐待(你刚才说了"强奸"吗?)超载操作员的最有趣的方式,也是用900磅重的炮弹射中自己脚的最佳方式之一。
enum { fold } fold_t;
template <typename Op>
struct fold_intermediate_1
{
Op op;
fold_intermediate_1 (Op op) : op(op) {}
};
template <typename Cont, typename Op, bool>
struct fold_intermediate_2
{
const Cont& cont;
Op op;
fold_intermediate_2 (const Cont& cont, Op op) : cont(cont), op(op) {}
};
template <typename Op>
fold_intermediate_1<Op> operator/(fold_t, Op op)
{
return fold_intermediate_1<Op>(op);
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, true> operator<(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, true>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator< (fold_intermediate_2<Cont, Op, true> f, Init init)
{
return foldl_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
template <typename Cont, typename Op>
fold_intermediate_2<Cont, Op, false> operator>(const Cont& cont, fold_intermediate_1<Op> f)
{
return fold_intermediate_2<Cont, Op, false>(cont, f.op);
}
template <typename Cont, typename Op, typename Init>
Init operator> (fold_intermediate_2<Cont, Op, false> f, Init init)
{
return foldr_func(f.op, init, std::begin(f.cont), std::end(f.cont));
}
CCD_ 20和CCD_。
这样使用:
foo myfunc(foo, foo);
container<foo> cont;
foo zero, acc;
acc = cont >fold/myfunc> zero; // right fold
acc = cont <fold/myfunc< zero; // left fold
fold
这个词在这里被用作穷人的一种新保留词。可以定义这种语法的几种变体,包括
<<fold/myfunc<< >>fold/myfunc>>
<foldl/myfunc> <foldr/myfunc>
|fold<myfunc| |fold>myfunc|
内部运算符的优先级必须与外部运算符的优先级相同或更高。这是C++语法的局限性。
对于map
,只需要一个中间体,语法可以是例如
mapped = cont |map| myfunc;
实现它是一个简单的练习。
哦,请不要在生产中使用这种语法,除非你非常清楚自己在做什么,甚至可能知道;)
- 将fold表达式与std::一起用于两个元组
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 我可以std::在fold表达式中转发参数吗
- 在fold表达式上枚举
- 如何从字符串"Fold a word"。前任。 "STACK"变得"SKTCA".C++
- map/fold运算符(在c++中)
- 使用 MPL::fold 与占位符和我自己的结构错误
- 从mpl-fold表达式中检索迭代器位置
- boost mpl fold占位符表达式无法编译
- 你能在fold表达式中使用子表达式吗
- 使用boost::fusion::fold将boost::fusion::set转换为boost::fusion::ma
- 如何实现嵌套提升::mpl::fold