Комбинаторы с фиксированной запятой в C++
-
02-07-2019 - |
Вопрос
Меня интересуют реальные примеры использования комбинаторов с фиксированной запятой (таких как Y-комбинатор в С++.Использовали ли вы когда-нибудь комбинатор с фиксированной запятой с яйцо или связывать в реальном живом коде?
Я нашел этот пример в яйце немного плотным:
void egg_example()
{
using bll::_1;
using bll::_2;
int r =
fix2(
bll::ret<int>(
// \(f,a) -> a == 0 ? 1 : a * f(a-1)
bll::if_then_else_return( _2 == 0,
1,
_2 * lazy(_1)(_2 - 1)
)
)
) (5);
BOOST_CHECK(r == 5*4*3*2*1);
}
Можете ли вы объяснить, как все это работает?
Есть ли хороший простой пример использования привязки с меньшим количеством зависимостей, чем этот?
Решение
Вот тот же код, преобразованный в boost::bind
обратите внимание на y-комбинатор и сайт его приложения в основной функции.Надеюсь, это поможет.
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
// Y-combinator compatible factorial
int fact(boost::function<int(int)> f,int v)
{
if(v == 0)
return 1;
else
return v * f(v -1);
}
// Y-combinator for the int type
boost::function<int(int)>
y(boost::function<int(boost::function<int(int)>,int)> f)
{
return boost::bind(f,boost::bind(&y,f),_1);
}
int main(int argc,char** argv)
{
boost::function<int(int)> factorial = y(fact);
std::cout << factorial(5) << std::endl;
return 0;
}
Другие советы
#include <functional>
#include <iostream>
template <typename Lamba, typename Type>
auto y (std::function<Type(Lamba, Type)> f) -> std::function<Type(Type)>
{
return std::bind(f, std::bind(&y<Lamba, Type>, f), std::placeholders::_1);
}
int main(int argc,char** argv)
{
std::cout << y < std::function<int(int)>, int> ([](std::function<int(int)> f, int x) {
return x == 0 ? 1 : x * f(x - 1);
}) (5) << std::endl;
return 0;
}
Можете ли вы объяснить, как все это работает?
fix2 — это y-комбинатор (точнее, это комбинатор для функций с двумя аргументами);первый аргумент — это функция (для целей рекурсии), второй аргумент — «правильный» аргумент функции).Он создает рекурсивные функции.
bll::ret(...) создает некую форму функционального объекта, тело которого
if(second arg == 0)
{
return 1;
}
else
{
return second arg * first arg(second arg - 1);
}
«Ленивый», по-видимому, предназначен для того, чтобы остановить бесконечное расширение первого аргумента (функции) (почитайте о разнице между ленивым и строгим y-комбинаторами, чтобы понять, почему).
Код довольно ужасен.Анонимные функции — это хорошо, но хакерство, позволяющее обойти отсутствие синтаксической поддержки в C++, делает их не стоящими затраченных усилий.