Reader C++ 运算符
Reader functor in C++
我正在尝试用 C++ 实现 reader 仿函数。
对应的Haskell定义是fmap :: (a -> b) -> (r -> a) -> (r -> b)
我的 C++ 版本是:
template<class A, class B, class R>
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
return funcA(funcR());
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
错误是:
note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-0)>' against 'double (std::__1::basic_string<char>)'
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
fmap函数的正确实现方式是什么?
问题是模板推导与类型完全匹配,无需转换。
您传入的函数指针与std::function
不是同一类型,因此模板参数的推导将失败。
正确的方法是将可调用对象作为模板参数。这确保了演绎会起作用。很多时候你不需要检查可调用函数的签名,因为如果它在函数中使用,如果以错误的方式使用它,你会得到一个编译时错误。
如果您仍想检查签名,使用类型特征并不难。
#include <string>
template<class A, class B>
B fmap(A a, B b) {
return a(b(std::string{}));
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
您可以使用来自
的简洁模板转换技巧来完成此操作
#include <functional>
#include <iostream>
#include <string>
using namespace std;
template<class T>
struct AsFunction
: public AsFunction<decltype(&T::operator())>
{};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(*)(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class Class, class ReturnType, class... Args>
struct AsFunction<ReturnType(Class::*)(Args...) const> {
using type = std::function<ReturnType(Args...)>;
};
template<class F>
auto toFunction(F f) -> typename AsFunction<F>::type {
return { f };
}
template<class A, class B, class R>
B fmap(const std::function<B(A)>& funcA, const std::function<A(R)>& funcR, R value) {
return funcA(funcR(value));
}
template <class T>
auto ToFunction(T t) {
return t;
}
std::string function_1(int n) {
return ""s;
}
double function_2(std::string s) {
return 0.0;
}
int main() {
fmap(toFunction(function_2), toFunction(function_1), 5);
return 0;
}
Bartosz Milewski 的著作《程序员的范畴论》(2014 年 19 月)
https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/
给出了 C++ 中 Writer 仿函数的示例...从那里生成 Reader 仿函数是一个更简单的步骤:
#include <string>
#include <functional>
using namespace std;
template<class R, class A, class B>
function<B(R)> Reader(function<A(R)> m1, function<B(A)> m2)
{
return [m1,m2] (R r) { return m2(m1(r)); };
}
// example
string repeat(string x) {return x+x;}
string i_to_s( int x) {return to_string(x);}
string process(int x) {
return Reader<int, string, string>(i_to_s, repeat)(x);}
我正在尝试用 C++ 实现 reader 仿函数。 对应的Haskell定义是fmap :: (a -> b) -> (r -> a) -> (r -> b)
我的 C++ 版本是:
template<class A, class B, class R>
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
return funcA(funcR());
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
错误是:
note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-0)>' against 'double (std::__1::basic_string<char>)'
B fmap(const std::function<B(A)> &funcA, const std::function<A(R)> &funcR) {
fmap函数的正确实现方式是什么?
问题是模板推导与类型完全匹配,无需转换。
您传入的函数指针与std::function
不是同一类型,因此模板参数的推导将失败。
正确的方法是将可调用对象作为模板参数。这确保了演绎会起作用。很多时候你不需要检查可调用函数的签名,因为如果它在函数中使用,如果以错误的方式使用它,你会得到一个编译时错误。
如果您仍想检查签名,使用类型特征并不难。
#include <string>
template<class A, class B>
B fmap(A a, B b) {
return a(b(std::string{}));
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);
您可以使用来自
#include <functional>
#include <iostream>
#include <string>
using namespace std;
template<class T>
struct AsFunction
: public AsFunction<decltype(&T::operator())>
{};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class ReturnType, class... Args>
struct AsFunction<ReturnType(*)(Args...)> {
using type = std::function<ReturnType(Args...)>;
};
template<class Class, class ReturnType, class... Args>
struct AsFunction<ReturnType(Class::*)(Args...) const> {
using type = std::function<ReturnType(Args...)>;
};
template<class F>
auto toFunction(F f) -> typename AsFunction<F>::type {
return { f };
}
template<class A, class B, class R>
B fmap(const std::function<B(A)>& funcA, const std::function<A(R)>& funcR, R value) {
return funcA(funcR(value));
}
template <class T>
auto ToFunction(T t) {
return t;
}
std::string function_1(int n) {
return ""s;
}
double function_2(std::string s) {
return 0.0;
}
int main() {
fmap(toFunction(function_2), toFunction(function_1), 5);
return 0;
}
Bartosz Milewski 的著作《程序员的范畴论》(2014 年 19 月) https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ 给出了 C++ 中 Writer 仿函数的示例...从那里生成 Reader 仿函数是一个更简单的步骤:
#include <string>
#include <functional>
using namespace std;
template<class R, class A, class B>
function<B(R)> Reader(function<A(R)> m1, function<B(A)> m2)
{
return [m1,m2] (R r) { return m2(m1(r)); };
}
// example
string repeat(string x) {return x+x;}
string i_to_s( int x) {return to_string(x);}
string process(int x) {
return Reader<int, string, string>(i_to_s, repeat)(x);}