2008-09-30 25 views
7

Jestem zainteresowany rzeczywistych przykładów stosując operator paradoksalny (takie jak y-combinator w C++. Czy kiedykolwiek użył operator paradoksalny z egg lub bind w prawdziwym kodzie żywo?kombinatorów ustalonym punkcie C++

I uznał ten przykład w jajku trochę gęstej:?

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

można wyjaśnić, jak to wszystko działa

jest tam ładny prostym przykładem może być może z użyciem wiążą mniej dependancies niż ten jeden

+0

Jeśli napiszesz kod, który wygląda na to, że nikt nigdy nie będzie w stanie go utrzymać, włącznie z tobą. –

+1

Nie chodzi o to, że naprawdę chcę pisać kombinatory punktowe lub lambdy w C++, ale raczej, że przykład tych w C++ byłby budujący dla kogoś takiego jak ja, który nie jest wszystkim obeznany z językami, w których mogą być bardziej przydatny. –

Odpowiedz

29

Oto ten sam kod, który został przekształcony w boost::bind, z informacją, że y-combinator i jego strona aplikacji znajdują się w głównej funkcji. Mam nadzieję, że to pomoże.

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

Tego właśnie szukałem. Chciałbym móc dwukrotnie głosować na ciebie –

3

Czy możesz wyjaśnić, jak to wszystko działa?

Fix2 jest y-syntezatora (w szczególności, jest to syntezatora dla funkcji z dwóch argumentów, a pierwszy argument jest funkcją (dla celów rekurencji), drugi argument jest „właściwa” funkcja argument) . Tworzy funkcje rekurencyjne.

BLL :: ret (...) wydaje się stworzyć jakąś formę obiektu funkcyjnego, ciało, które jest

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

z „leniwe” jest przypuszczalnie tam zatrzymać nieskończoną ekspansję pierwszy (funkcja) argument (odczytaj różnicę między leniwymi i ścisłymi kombinatorami y, aby zobaczyć dlaczego).

Kod jest dość okropny. Anonimowe funkcje są przyjemne, ale hackery do pracy z brakiem wsparcia syntaktycznego w C++ sprawiają, że nie są warte wysiłku.

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

Działa wspaniale i jest również czysty C++ 11 – Tony

+1

Jedynym problemem związanym z tym i z zaakceptowaną odpowiedzią opartą na bodźcu jest to, że zgodnie z moimi wskazaniami na temat kombinatora Y, ściśle mówiąc, nie wolno sama nazwa w swojej definicji. – Tony