- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在玩弄 C++11 lambda,并试图模仿 functional
module 中的一些函数。 D 编程语言。我实际上是在尝试实现 curry
和 compose
.这里是 main
我正在努力工作:
int main()
{
auto add = [](int a, int b)
{
return a + b;
};
auto add5 = curry(add, 5);
auto composed = compose(add5, add);
// Expected result: 25
std::cout << composed(5, 15) << std::endl;
}
问题是我没有从 g++ 和 clang++ 得到相同的结果。我明白了:
g++ 4.8.2 和 4.9 给了我预期的结果。从 g++ 4.8.1 和 clang 3.5 得到的结果不依赖于传递给 curry
的值。 .我最初认为这可能是编译器错误,但更有可能是我的代码有错误。
这是我对 curry
的实现:
template<typename Function, typename First, std::size_t... Ind>
auto curry_impl(const Function& func, First&& first, indices<Ind...>)
-> std::function<
typename function_traits<Function>::result_type(
typename function_traits<Function>::template argument_type<Ind>...)>
{
return [&](typename function_traits<Function>::template argument_type<Ind>&&... args)
{
return func(
std::forward<First>(first),
std::forward<typename function_traits<Function>::template argument_type<Ind>>(args)...
);
};
}
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
using FirstArg = typename function_traits<Function>::template argument_type<0>;
static_assert(std::is_convertible<First, FirstArg>::value,
"the value to be tied should be convertible to the type of the function's first parameter");
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
这是我对 compose
的实现(注意我只写了一个二进制 compose
而 D 是可变的):
template<typename First, typename Second, std::size_t... Ind>
auto compose_impl(const First& first, const Second& second, indices<Ind...>)
-> std::function<
typename function_traits<First>::result_type(
typename function_traits<Second>::template argument_type<Ind>...)>
{
return [&](typename function_traits<Second>::template argument_type<Ind>&&... args)
{
return first(second(
std::forward<typename function_traits<Second>::template argument_type<Ind>>(args)...
));
};
}
template<typename First, typename Second,
typename Indices=make_indices<function_traits<Second>::arity>>
auto compose(First&& first, Second&& second)
-> decltype(compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices()))
{
static_assert(function_traits<First>::arity == 1u,
"all the functions passed to compose, except the last one, must take exactly one parameter");
using Ret = typename function_traits<Second>::result_type;
using FirstArg = typename function_traits<First>::template argument_type<0>;
static_assert(std::is_convertible<Ret, FirstArg>::value,
"incompatible return types in compose");
return compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices());
}
类(class)function_trait
用于获取 lambda 的arity、返回类型和参数类型。此代码严重依赖索引技巧。由于我不用C++14,所以不用 std::index_sequence
但名称为 indices
的较旧实现. indices_range<begin, end>
是对应于 [begin, end)
范围的索引序列.您可以找到这些辅助元函数的实现(以及 curry
和 compose
)on the online version of the code ,但它们在这个问题上意义不大。
我在 curry
的实现中是否有错误?和/或 compose
还是由于编译器错误导致的不良结果(使用 g++ 4.8.1 和 clang++ 3.5)?
编辑:您可能会发现上面的代码不太可读。所以,这里是 curry
的版本和 compose
它们完全相同,但使用别名模板来减少样板。我还删除了 static_assert
小号;虽然它们可能是有用的信息,但对于问题而言,这只是太多的文字,而且它们不会在手头的问题中发挥作用。
template<typename Function, typename First, std::size_t... Ind>
auto curry_impl(const Function& func, First&& first, indices<Ind...>)
-> std::function<
result_type<Function>(
argument_type<Function, Ind>...)>
{
return [&](argument_type<Function, Ind>&&... args)
{
return func(
std::forward<First>(first),
std::forward<argument_type<Function, Ind>>(args)...
);
};
}
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
template<typename First, typename Second, std::size_t... Ind>
auto compose_impl(const First& first, const Second& second, indices<Ind...>)
-> std::function<
typename result_type<First>(
typename argument_type<Second, Ind>...)>
{
return [&](argument_type<Second, Ind>&&... args)
{
return first(second(
std::forward<argument_type<Second, Ind>>(args)...
));
};
}
template<typename First, typename Second,
typename Indices=make_indices<function_traits<Second>::arity>>
auto compose(First&& first, Second&& second)
-> decltype(compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices()))
{
return compose_impl(std::forward<First>(first), std::forward<Second>(second), Indices());
}
最佳答案
我相信其他人在您的评论中已经提到,与您的代码相关的问题是终身问题。请注意,您将第二个参数 5
作为右值传递给 curry
:
auto add5 = curry(add, 5);
然后,在调用 curry
函数时,您将在堆栈上创建该变量的拷贝作为参数之一:
auto curry(Function&& func, First first)
然后,在您对 curry_impl
的调用中,您传递对 first
的引用,一旦对 curry
的调用完成,该引用将不存在。由于您正在生成的 lambda 使用对不再存在的变量的引用,因此您会得到未定义的行为。
要解决您遇到的问题,只需将 curry
的原型(prototype)更改为使用对 first
的通用引用,并确保不将右值传递给 curry
:
template<typename Function, typename First,
typename Indices=indices_range<1, function_traits<Function>::arity>>
auto curry(Function&& func, First&& first)
-> decltype(curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices()))
{
using FirstArg = typename function_traits<Function>::template argument_type<0>;
static_assert(std::is_convertible<First, FirstArg>::value,
"the value to be tied should be convertible to the type of the function's first parameter");
return curry_impl(std::forward<Function>(func), std::forward<First>(first), Indices());
}
然后在main中:
int foo = 5;
auto add5 = curry(add, foo);
当然,将自己限制为左值表达式是接口(interface)的一个相当大的问题,因此值得一提的是,如果您打算在练习之外使用它,最好提供一个可以使用右值的接口(interface)用过。
再一次,我将对其进行更改,以便生成的仿函数拥有其组件的拷贝,就像 std::bind
一样。我知道如果以下代码不起作用,我会有点困惑:
std::function<int(int)> foo()
{
std::function<int(int, int)> add = [](int a, int b)
{
return a + b;
};
return curry(add, 5);
}
编辑:我现在看到某些版本的 gcc 仍然需要将值按值捕获到生成的 Lamba 中。 GCC 4.9.0 20131229 是我测试过的版本,运行良好。
编辑 #2:根据 Xeo 指定正确用法
关于c++ - 尝试将 curried lambda 与另一个 lambda 组合时出现意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23205241/
可以使用 lambda 和函数创建有序对(Lisp 中的缺点),如 Use of lambda for cons/car/cdr definition in SICP 所示。 它也适用于 Python
我正在尝试从另一个调用一个 AWS lambda 并执行 lambda 链接。这样做的理由是 AWS 不提供来自同一个 S3 存储桶的多个触发器。 我创建了一个带有 s3 触发器的 lambda。第一
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。 fun main(args: Array) { val numbers = listOf(1, 2, 3) f
A Tutorial Introduction to the Lambda Calculus 本文介绍乘法函数 The multiplication of two numbers x and y ca
我想弄清楚如何为下面的表达式绘制语法树。首先,这究竟是如何表现的?看样子是以1和2为参数,如果n是 0,它只会返回 m . 另外,有人可以指出解析树的开始,还是一个例子?我一直找不到一个。 最佳答案
在 C++0x 中,我想知道 lambda 函数的类型是什么。具体来说: #include type1 foo(int x){ return [x](int y)->int{return x * y
我在其中一个职位发布中看到了这个问题,它询问什么是 lambda 函数以及它与高阶函数的关系。我已经知道如何使用 lambda 函数,但不太自信地解释它,所以我做了一点谷歌搜索,发现了这个:What
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
我正在处理 MyCustomType 的实例集合如下: fun runAll(vararg commands: MyCustomType){ commands.forEach { it.myM
Brian 在他对问题 "Are side effects a good thing?" 的论证中的前提很有趣: computers are von-Neumann machines that are
在 Common Lisp 中,如果我希望两个函数共享状态,我将按如下方式执行 let over lambda: (let ((state 1)) (defun inc-state () (in
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
作为lambda calculus wiki说: There are several possible ways to define the natural numbers in lambda cal
我有一个数据类,我需要初始化一些 List .我需要获取 JsonArray 的值(我使用的是 Gson)。 我做了这个函数: private fun arrayToList(data: JsonAr
((lambda () )) 的方案中是否有简写 例如,代替 ((lambda () (define x 1) (display x))) 我希望能够做类似的事情 (empty-lam
我在 Java library 中有以下方法: public void setColumnComparator(final int columnIndex, final Comparator colu
我正在研究一个函数来计算国际象棋游戏中棋子的有效移动。 white-pawn-move 函数有效。当我试图将其概括为任一玩家的棋子 (pawn-move) 时,我遇到了非法函数调用。我已经在 repl
考虑这段代码(在 GCC 和 MSVC 上编译): int main() { auto foo = [](auto p){ typedef decltype(p) p_t;
我正在阅读一个在 lambda 内部使用 lambda 的片段,然后我想通过创建一个虚拟函数来测试它,该函数从文件中读取然后返回最大和最小数字。 这是我想出来的 dummy = lambda path
我是一名优秀的程序员,十分优秀!