LINUX.ORG.RU

Аналоги функций высшего порядка в С++

 , ,


1

4

Допустим, некто попал на необитаемый остров без интернета, и у него только компьютер с про^W С++ - никаких функиональных языков. Ему хочется попробовать реализовать reduce, map, fold etc. самому и на С++. То есть должна быть функция, которая принимала бы контейнер, аккумулятор и операцию-функцию. Что ему делать? Указатели на функции? Функторы? Какие-то извращенские шаблоны или что еще можно придумать? Некто с удовольствием бы почитал манов на тему, но сразу как-то не нагуглилось.

★★★★★

Можно написать на C++ компилятор хаскелла.

provaton ★★★★★
()

Я предпочитаю передавать функции как аргументы шаблона, например. В stl и thrust используются functional objects.

dmfd
()
Ответ на: комментарий от dmfd

Вообще, стоит посмотреть, как сделаны те же самые stl и thrust. Они как раз под впечатлением от функциональщины и были разработаны.

dmfd
()
Ответ на: комментарий от cdshines

«LMD» - это было замечание относительно твоего уровня развития, и пожелание тебе соответствующего исхода. Ибо как минимум гуглом пользоваться любой не-ламер должен уметь.

anonymous
()

reduce

std::accumulate

map

std::transform

anonymous
()
Ответ на: комментарий от dmfd

О, прямо как я хотел:

int x = thrust::reduce(d_vec.begin(), d_vec.end(), 0, thrust::plus<int>());

template<typename T>
  struct plus : public binary_function<T,T,T>
{
  __host__ __device__ T operator()(const T &lhs, const T &rhs) const {return lhs + rhs;}
};
cdshines ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Ох, а я думал, ты хороший. А ты плохой, уходи.

cdshines ★★★★★
() автор топика
Ответ на: комментарий от dmfd

Как вы умудрились не знать про STL?

Я ж говорю - LMD.

anonymous
()
Ответ на: комментарий от dmfd

Но это только для CUDA

Так я не буду ими пользоваться, мне захотелось что-то такое свелосипедить просто для себя. Поэтому я и спросил, как делается, а не какие библиотеки. Ну и STL тоже поэтому не вспомнил.

cdshines ★★★★★
() автор топика
Последнее исправление: cdshines (всего исправлений: 1)
Ответ на: комментарий от cdshines

А не-ламер, прежде чем велосипедить, посмотрел бы, как другие делают, и на чужих бы ошибках поучился.

anonymous
()

Указатели на функции?

оно. Правда оно не очень быстро будет, если функции типа

int add_int(int x, int y)
{
    return x + y;
}

drBatty ★★
()
Ответ на: комментарий от dmfd

Как вы умудрились не знать про STL?

а я так понял вопрос ТСа, что у него нет никакого stl.

drBatty ★★
()
Ответ на: комментарий от drBatty

Поэтому я и спросил. Ты не пробовал проводить тренинги или какие-то семинары? Что-то вроде «Уроки жизни от Подставить Имя»? Нет? Зря.

cdshines ★★★★★
() автор топика
Ответ на: комментарий от cdshines

Что-то вроде «Уроки жизни от Подставить Имя»? Нет? Зря.

идея здравая, думаю попробовать. Вопрос лишь в поиске клиентуры.

drBatty ★★
()
Ответ на: комментарий от cdshines

Ой, это я не тебе. Жалко, что анонимусов нельзя кастовать, но этот и так настырный - все лезет и лезет.

Я просто тыкнул под твоим ником Ответить, потому что хотел спросить, почему не быстро?

cdshines ★★★★★
() автор топика
Ответ на: комментарий от drBatty

был.

Возвращайся, тут твою задорновщину про пьяных русских никто не поймёт.

anonymous
()

C++11: std::function + лямбды. В стандартной библиотеке есть готовые алгоритмы.

// принимаем функцию
int foo(std::function<int(int,int)> f, int a, int b)
{
    return f(a, b);
}

// передаем в функцию лямбду
int x = foo([](int a, int b) {return a + b}, 10, 20);

Если не хочется std::function - можно просто шаблон:

template<typename F>
int foo(F f, int a, int b);

Остальное - так же.

anonymous
()
Ответ на: комментарий от anonymous

нет, я не против std::function.

итого, все по-разному ответили. вопрос как раз был - что сюда лучше подходит с т.з. того, что мои алгоритмы будут черным ящиком, а посторонние люди просто должны будут писать свои операции. что лучше/проще?

cdshines ★★★★★
() автор топика
Ответ на: комментарий от cdshines

С одной стороны, проще std::function т.к. он дает возможность работать без шаблонов, т.е. сможешь сделать «обычные» либы, например. С другой, как раз обобщенный код может быть лучшим с точки зрения архитектуры и производительности...

anonymous
()
Ответ на: комментарий от anonymous

А что мешает писать обобщенные методы? Прям так сложно слово template написать? Или не хочется из содержимым светить?

Gorthauer ★★★★★
()
Ответ на: комментарий от anonymous

Ты не понял меня, но я рад, что ты повеселел.

anonymous
()
Ответ на: комментарий от anonymous

Видимо имелось в виду то, что по ссылке, идущий вместе с LMD=)

anonymous
()

Функциональное программирование (ФП) без системы автоматического управления памятью - то еще зрелище! Сходят на нет основные плюшки ФП, как то: замыкания с неопределенным временем жизни (да-да, вот она другая личина функций высшего порядка), да персистентные данные, причем в последнем случае могут быть циклические/рекурсивные данные. В общем, не страдай фигней или выбери другой язык :)

dave ★★★★★
()
Ответ на: комментарий от dave

С замыканиями справится семантика значений и смарты для больших данных.

С персистентными структурами std::shared_ptr + std::weak_ptr так же справятся.

А язык, безусловно, выбирать нужно. Но не исходя из каких-то сферических коней в вакууме, а из реальных требований.

anonymous
()
Ответ на: комментарий от anonymous

Обходные пути, разумеется, иногда существуют [1]. Кому как, но мне кажется, что ФП выглядит в Си++ как-то противоестественно, если это не что-то примитивное типа «функторов» STL. Однако, сейчас мода на ФП, как лет двадцать-тридцать назад была мода на ООП.

[1] Бывает, что эти обходные пути ведут к потере в производительности по сравнению с языками, заточенными на функциональный стиль. Встречались бенчмарки, но пруфа с моей стороны сейчас не будет. «Нулевая стоимость» в Си++ является обычным мифом, которые сопровождают многие языки. У других языков - другие мифы: «эффект Блаба», «кривая половина CL», «написано однажды - работает везде», «только один способ написать код», «более безопасный код через тотальную чистоту благодаря ссылочной прозрачности», «циклические данные - ошибка дизайна» и т.п.

dave ★★★★★
()
Ответ на: комментарий от dave

Это не обходные пути. Полноценные функции высшего порядка в С++ есть, как и полноценные замыкания(более того, они в С++ предоставляют контроль за тем, как именно захватывать). Но это не значит, что язык должен потерять возможность ручного управления памятью(достоинством которого является единообразное и своевременное освобождение любых ресурсов, в том числе и памяти). Прикрутите GC к С++(консервативный уже есть, можно сделать и более оптимальный за счет введения еще одного типа *_ptr) - сможете использовать замыкания не думая о памяти, как и в любом языке с GC.

Это и есть та самая нулевая стоимость, которую вы считаете мифом. Если мне нужны замыкания, но не нужен GC, я не буду использовать GC и не буду за него платить. Замыкание в языке не привели к лишнему оверхеду. Если я не буду их использовать - я не буду и платить.

Кстати, парадокс Блаба - тоже не миф. Я в этом и на собственном опыте убедился. С разными языками(самый существенный эффект был с прологом).

anonymous
()
Ответ на: комментарий от lazyklimm

если указатели на функции - это полноценный аналог ФВП

если ты мне дашь ссылку, на тот пост, где я такой бред написал - посмеёмся вместе.

drBatty ★★
()
Ответ на: комментарий от dave

«Нулевая стоимость» в Си++ является обычным мифом

в данном случае стоимость в принципе не может быть нулевой. Где-то всё равно надо хранить указатель на функцию, даже если компилятор иногда его и выкидывает.

drBatty ★★
()
Ответ на: комментарий от anonymous

Кстати, парадокс Блаба - тоже не миф. Я в этом и на собственном опыте убедился.

парадокс блаба субъективен. А почему «блаб» с большой буквы? Мы про что вообще?

drBatty ★★
()
Ответ на: комментарий от drBatty

Принцип нулевой стоимости говорит о нулевой стоимости того, что ты НЕ используешь. Это дальнейшей развитие идей сишечки. Если в ней вообще практически нет рантайма, то в С++ он есть, но оверхед от фичи у тебя будет только в том случае, если тебе это фича нужна. Причем оверхед будет небольшим(но это уже не имеет отношения к обсуждаемому принципу)

anonymous
()
Ответ на: комментарий от anonymous

Принцип нулевой стоимости говорит о нулевой стоимости того, что ты НЕ используешь. Это дальнейшей развитие идей сишечки. Если в ней вообще практически нет рантайма, то в С++ он есть, но оверхед от фичи у тебя будет только в том случае, если тебе это фича нужна.

что-то я не понимаю, как ты вычисляешь оверхед от лямбд в LISP, ежели ты лямбды не юзаешь?

ТС между прочим прямо сформулировал: «То есть должна быть функция, которая принимала бы контейнер, аккумулятор и операцию-функцию.» Согласись, templates из C++ это немного не то, и хоть из них и можно что-то похожее изобразить, но это пилить надо. А вот STL (где уже допилили) ИМХО не C++. Да и C++11 тем более. Хотя в последнем вполне себе функциональные во всех смыслах лямбды.

drBatty ★★
()
Ответ на: комментарий от drBatty

Даже если ты не юзаешь лямбды в лиспе ты за них платишь - ибо их(в том числе) поддержка в языке приводит к определенной реализации скопов, обязательной сборки мусора и пр. В С++ - нет.

В С++98 есть «функторы» - вручную созданные объекты с «замыканием»(ручным) и operator(). В сочитании с template их можно использовать как функции-объекты-первого-рода. Без шаблонов - через boost::function<возвращаемый-тип(тип-аргумента1, тип-аргумента2, ... тип-аргументаN)>. И не забываем про boost::bind.

В новом стандарте есть std::function и появились лямбды. Чего тебе еще не хватает?

anonymous
()
Ответ на: комментарий от anonymous

Даже если ты не юзаешь лямбды в лиспе ты за них платишь - ибо их(в том числе) поддержка в языке приводит к определенной реализации скопов, обязательной сборки мусора и пр. В С++ - нет.

с одной стороны это привело к тому, что лямбды без скопов в C++ дефектные by design, а с другой - к тому что компиллится эта ерунда уж очень долго.

В С++98 есть «функторы» - вручную созданные объекты с «замыканием»(ручным) и operator().

У Страуструпа их не было что-ли?

Без шаблонов - через boost::function<возвращаемый-тип(тип-аргумента1, тип-аргумента2, ... тип-аргументаN)>

это тоже шаблон, а не рантаймовая лямбда. Лямбды в принципе реализуются только в рантайме, а в шаблонах это ерунда, а не лямбда. Да и даже если лямбда реализована в рантайме, то она должна поддерживать рантаймовый же скоп. Свой личный. А не как в C++11.

Короче - придётся признать, что в C++ полноценных лямбд как небыло, так и нет. И видимо не будет. За исключение плясок с бубном вокруг указателя на функцию и макросы/шаблоны.

drBatty ★★
()
Ответ на: комментарий от drBatty

Что не так с лямбдами в С++? На время компиляции их появление не повлияло

boost::function<> шаблонен исключительно в части типов параметров и возвращаемого значения. А по другому в языках со статической типизацией не бывает. Чем function<int(int)> принципиально хуже int->int в каком-нибудь функциональном языке?

Что значит она должна поддерживать свой личный рантаймовый скоп?

function<int(int)> foo(int x)
{
    return [=](int y) { return x + y; };
}
anonymous
()
Ответ на: комментарий от drBatty

Ты так и не объяснил, чем лямбды в С++ не полноценны? Приведи код что ли с лямбдами в другом языке, чтоб на С++ не ложился.

anonymous
()
Ответ на: комментарий от anonymous

Ты действительно идиот? Не можешь представить себе кода с непредсказуемым временем жизни замыкания?

anonymous
()
Ответ на: комментарий от anonymous

Ну ты же можешь? Так покажи. Тут ведь нужен такой код, чтоб смарты не справились.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.