没有参数的函数只是 Haskell 中的一个值。你不调用它,你只是使用它。由于没有副作用,因此没有可观察到的差异。
在 OCaml 中根本没有无参数函数,要获得类似的东西,您需要添加一个虚拟单元参数。
在 C++ 中并非如此。f
与 Haskell 和 OCaml 不同,C++ 在和之间保持明显的区别f()
。bind
给你前者,因为你总是可以通过添加将它变成后者()
。您可以为此编写自己的包装器,bind
这很容易。反其道而行之,难度会大一些。
这是这种包装器的可能实现:
#include <functional>
#include <utility>
#include <iostream>
template <typename T>
struct is_noargs_callable {
private:
typedef char(&yes)[1];
typedef char(&no)[2];
template<typename U>
static yes test(decltype((std::declval<U>())())*);
template<typename>
static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template <typename T>
struct is_noargs_callable<T()> {
static const bool value = true;
};
template <typename T>
struct is_noargs_callable<T(...)> {
static const bool value = true;
};
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<is_noargs_callable<T>::value, decltype(t())>::type
{
return t();
}
template <typename T>
auto call_me_if_you_can(T t) -> typename std::enable_if<!is_noargs_callable<T>::value, T>::type
{
return t;
}
template <typename... Args>
auto apply(Args&&... args) -> decltype(call_me_if_you_can(std::bind(args...))) {
return call_me_if_you_can(std::bind(args...));
}
// testing
void foo(int a, int b, int c) { std::cout << "foo(" << a << "," << b << "," << c << ")"; }
int main ()
{
using namespace std::placeholders;
std::cout << "zero : " ; apply(foo, _1, _2, _3); std::cout << " : " ; apply(foo, _1, _2, _3)(1,2,3); std::cout << std::endl;
std::cout << "one : " ; apply(foo, 1, _1, _2); std::cout << " : " ; apply(foo, 1, _1, _2)(2,3); std::cout << std::endl;
std::cout << "two : " ; apply(foo, 1, 2, _1); std::cout << " : " ; apply(foo, 1, 2, _1)(3); std::cout << std::endl;
std::cout << "three: " ; apply(foo, 1, 2, 3); std::cout << " : "; /* nothing to test here */ std::cout << std::endl;
}
然而,在这一个地方消除和之间的区别f
并f()
不能恕我直言,有助于 C++ 编程的整体一致性。如果您不喜欢这种区别,请在任何地方杀死它(或者只是为您使用 Haskell)。