Pregunta

Me interesan los ejemplos reales de uso de combinadores de puntos fijos (como y-combinator en C ++. ¿Alguna vez ha usado un combinador de punto fijo con egg o enlazar en código real en vivo?

Encontré este ejemplo en huevo un poco denso:

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);
}

¿Puedes explicar cómo funciona todo esto?

¿Hay un buen ejemplo simple que quizás use bind con quizás menos dependencias que este?

¿Fue útil?

Solución

Aquí está el mismo código convertido en boost :: bind , observe el combinador y y su sitio de aplicación en la función principal. Espero que esto ayude.

#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;
}

Otros consejos

#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;
}
  

¿Puedes explicar cómo funciona todo esto?

fix2 es un combinador de y (específicamente, es un combinador para funciones con dos argumentos; el primer argumento es la función (para el propósito de la recursión), el segundo argumento es un argumento de función apropiado). Crea funciones recursivas.

bll :: ret (...) parece crear alguna forma de un objeto de función, cuyo cuerpo es

if(second arg == 0)
{
    return 1;
}
else
{
    return second arg * first arg(second arg - 1);
}

El " perezoso " es probable que esté ahí para detener una expansión infinita del primer argumento (función) (lea la diferencia entre combinadores perezosos y estrictos para ver por qué).

El código es bastante horrible. Es agradable tener funciones anónimas, pero la piratería para solucionar la falta de soporte sintáctico de C ++ hace que no valgan la pena.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top