Как я могу решить SICP 2.4 в C ++ 11

Это упражнение попросить осуществить cons, car а также cdr функции, использующие только лямбда-функции.

Функция cons(a,b) создать список a с последующим b, car(l) возвращает первый элемент списка l, а также cdr(l) возвращает остальную часть списка.

Я работал со списками только из двух элементов, но когда вы пытаетесь обработать больше элементов, это терпит неудачу. Есть идеи?

#include <iostream>
#include <functional>

template<typename A>
A car( std::function< A(std::function<A(A,A)>) > m ){
return m( [](A a, A){ return a; } );
}

template<typename A>
A cdr( std::function< A(std::function<A(A,A)>) > m ){
return m( [](A, A b){ return b; } );
}

template<typename A>
std::function< A(std::function<A(A,A)>) >
cons( const A a, const A b){
return [=](std::function<A(A,A)> l){ return l(a,b); };
}

int main(){
//auto l = cons( cons( 1, 2 ), 3 );  // no matching function
auto l = cons( 1, 2 );

std::cout << car( l ) << ", " << cdr( l ) << std::endl;

return 0;
}

ОБНОВИТЬ

Я замечаю, что настоящая подпись минусов должна быть:

template<typename A,typename B, typename C>
std::function< C(std::function<C(A,B)>) >
cons( const A a, const B b){
return [=](std::function<C(A,B)> l){ return l(a,b); };
}

Потому что эта версия тоже не работала.

ОБНОВЛЕНИЕ 2
Это может быть упрощено (более читабельно) с помощью:

template<typename A, typename B, typename C>
using Cell<A,B,C> = std::function<C(A,B)>

0

Решение

cons из вашего примера не может быть скомпилировано, потому что компилятор не может вывести тип возврата для лямбда-функции. Что вам нужно, так это полиморфная лямбда-функция. К сожалению, C ++ 11 не поддерживает полиморфные лямбды, но есть несколько способов реализовать cons, car а также cdr в любом случае в C ++.

Первый (и, возможно, самый простой) способ реализации cons, car а также cdr использует std::tuple или же std::pair, Эта реализация почти аналогична определениям в глава 2.1.3 книги.

#include <iostream>
#include <tuple>

template<typename A, typename B>
A car( std::tuple<A, B> m ) {
return std::get<0>(m);
}

template<typename A, typename B>
B car( std::tuple<A, B> m ) {
return std::get<1>(m);
}

template<typename A, typename B>
std::tuple<A, B>
cons(const A a, const B b) {
return std::tuple<A, B>(a, b);
}

int main() {
auto l = cons(cons(1, 2), 3);
std::cout << car(car(l)) << ", " << cdr(car(l)) << ", ";
std::cout << cdr(l) << std::endl;

return 0;
}

Но эта реализация не следует первоначальной идее упражнение 2.4. Чтобы следовать этому, мы могли бы просто создать свой собственный pair класс и реализовать operator() метод параметризован лямбда-типом возврата.

#include <iostream>
#include <functional>

template<typename A, typename B>
class pair {
A _a;
B _b;

public:
pair(const A a, const B b): _a(a), _b(b) {}

template<typename R>
R operator()(std::function<R(A, B)> func) {
return func(_a, _b);
}
};

И тогда мы могли бы реализовать cons, car а также cdr просто используя это:

template<typename A, typename B>
A car(pair<A, B> p) {
return p( std::function<A(A, B)> ( [](A a, B) { return a; } ) );
}

template<typename A, typename B>
B cdr(pair<A, B> p) {
return p( std::function<B(A, B)> ( [](A, B b) { return b; } ) );
}

template<typename A, typename B>
pair<A, B>
cons(const A a, const B b) {
return pair<A, B>(a, b);
}

int main() {
auto p = cons(cons("a", 2), 3);
std::cout << car(car(p)) << ", " << cdr(car(p)) << ", ";
std::cout << cdr(p) << std::endl;

return 0;
}

Насколько я понимаю, C ++ 14 (условно названный C ++ 1y) представит некоторые функции, такие как общие лямбда-выражения, которые могут упростить реализацию.

ОБНОВИТЬ

После прочтения предложение общих (полиморфных) лямбда-выражений в C ++ 14 я пришел к следующей рабочей реализации:

#include <iostream>

auto car = [](auto func) { return func( [](auto a, auto b) { return a; } ); };
auto cdr = [](auto func) { return func( [](auto a, auto b) { return b; } ); };
auto cons = [](auto a, auto b) { return [=](auto func) { return func(a, b); }; };

int main() {
auto p = cons( cons("a", 2), 3 );
std::cout << car(car(p)) << ", " << cdr(car(p)) << ", ";
std::cout << cdr(p) << std::endl;

return 0;
}

Обратите внимание, что он будет работать только с компилятором, реализующим такое предложение (например, GCC 4.8, Clang 3.4) с использованием -std=c++1y флаг.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]