LINUX.ORG.RU
ФорумTalks

лямбды в новых язычках - PR или реальные полезняшки?

 , ,


7

7

Народ, а поясните пожалуйста, что конкретно имеется ввиду, когда некто, описывая всякие плюшки новорожденного языка восторженно заявляет «там есть лямбды!».

Ну что есть lambda в каком-нибудь lisp я представляю и даже понимаю зачем оно и как им пользоваться. В lisp'е. А что имеется ввиду под «лямбдой» например, в C#?

Хотелось бы увидеть не только цитаты из википедии, а простенькие примеры того, как эта лямбда сильно упрощает жизнь, удобство даёт и всё такое. В виде примера кода, разумеется, с пояснениями почему тут именно лямбда крута и без неё некузяво.

Только чтобы это не было аналогом перлового однострочника типа

perl -e 'print sub{ $_[0] + $_[1]; }->(1,2)."\n";'
ибо в этом никаких новшеств и преимуществ нету.

Просто сдаётся мне что «лямбда» в нынешних сишарпах это пиарное название допотопных безымянных функций которые даже в перле есть и никаких новшеств в этом на самом деле нету.

★★★★★

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

фишка в том, что в ИП это НЕ НУЖНО

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

Внезапно, техники из ФП языков бывают полезны и в языках с другой парадигмой.

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

arr map(toInt) select(more(20)) sort uniq map(toString) join(", ")

А теперь напиши это же на сишечке и сравни объем кода.

расскажешь, как это работает - напишу.

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

Ниасилятор?

#include <stdio.h>

class A {
public:
        void data_appeared(const char * data, size_t size) {
                printf("%lu bytes read\n", size);
        }
};

template<typename T> void read_data(T callback)
{
        // network send/recv/wtf is here
        callback("data", 10);
}

int main()
{
        A a;
        read_data([&a](const char * data, size_t size) { a.data_appeared(data,size); }); // nowait is here
}
$ g++ 12.cpp -std=c++0x
$ ./a.out
10 bytes read
Reset ★★★★★
()
Последнее исправление: Reset (всего исправлений: 1)
Ответ на: комментарий от tailgunner

add(1, 2)

указатель на функцию. Пример см. выше.

incr = lambda y: add(1, y)

опять указатель на функцию(например такую, которая принимает другой указатель на другую функцию. Или на такую же)

def f(x): return lambda y: x+y

функция возвращающая указатель на функцию.

И что?

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

Т.е. ты будешь утверждать что разницы между указателем на функцию и ламбдой (замыканием) нет?

ну в вышеприведённых примерах на пайтоне - нет. Конечно в ФП есть. Но там и функции имеют совсем иной смысл.

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

функция возвращающая указатель на функцию.

А замыкание как ты будешь делать?

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

Лямбды значительно сокращают код, в сишке ты так не сделаешь.

В твоих примерах это оправдано только для тривиальных функций типа { x > 5; }, если функция достаточно сложная, то пара лишних строчек и своё имя функции не помешают. IRL функции мне попадаются достаочно сложные, практически все, кроме затычек, которые я либо не планирую делать вообще, либо планирую делать потом. Либо они имеют смысл только в производных классах (это в C++ pure virtual).

Зачем тебе нужна функция { return x > 5; } - мне непонятно.

К типам это тоже относится.

В итоге - если верить тебе, то выходит, что лямбды нужны только в helloworld или в таком коде, где очень много затычек.

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

Внезапно, техники из ФП языков бывают полезны и в языках с другой парадигмой.

ВНЕЗАПНО я не говорил, что они вредны или не нужны. Я спросил «зачем?»

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

Зачем тебе нужна функция { return x > 5; } - мне непонятно.

Например, чтобы отфильтровать данные.

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

Зачем тебе нужна функция { return x > 5; } - мне непонятно

Для декларативной фильтрации списка. Как ты будешь решать эту задачу, писать цикл на каждый чих?

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

Я спросил «зачем?»

Потому что они ПОЛЕЗНЫ. Что я (и остальные) и пытаюсь тебе втолковать. В ряде случаев они позволяют сократить код, сделать его более читаемым и лаконичным. Или удобство программирования — это уже не критерий?

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

read_data([&a](const char * data, size_t size) { a.data_appeared(data,size); }); // nowait is here

любопытный способ передачи в функцию указателя на метод класса... Но если read_data() у тебя всё равно шаблон, то почему ты не можешь описать callback как T::* ?

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

Этот код на си эквивалентен твоему коду на пхп. И в нём нет никаких лямбд.

Этот код — просто маленький пример того, какие приемущества дает использование лямбд по сравнению с их неиспользованием. То, что там «нет лямбд» может быть верным или неверным в зависимости от контекста. Например: в пхп есть лямбды и предача функционального аргумента есть одно свойств из лямбды -> этот код на пхп использует лямбды.

Сколько именно - хрен знает, но согласись, это получше твоего void*.

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

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

указателя на метод класса...

Это техника из 90х, которая неудобна, неэффективна, многословна, негибка. Сейчас за «указатель на метод класса» в приличном обществе вешают за яйца.

Но если read_data() у тебя всё равно шаблон, то почему ты не можешь описать callback как T::* ?

Ну а если мне надо частичное связывание сделать? Ну есть конечно boost::bind, что по сути почти те же яйца, только менее гибкие.

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

Конечно в ФП есть. Но там и функции имеют совсем иной смысл.

То есть, ненужность лямбд ты демонстрируешь на примере языка, где «функции имеют совсем иной смысл»? Одобряю!

linuxnewb
()
Ответ на: комментарий от Reset
#include <stdio.h>

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

int minus(int x, int y)
{
	return x - y;
}

typedef int (*ptr)(int, int);

ptr op(char c)
{
	switch(c)
	{
		case '+':
			return plus;
		case '-':
			return minus;
	}
	return NULL;
}

int main(void)
{
	ptr f = op('+');
	printf("2 + 3 = %d\n", f(2, 3));
	return 0;
}
drBatty ★★
()
Ответ на: комментарий от theNamelessOne

Аналог этого:

можно сделать на препроцессоре + GNU C, но я соглашусь с drBatty - ничего действительно нужного, вот без чего жить трудно, еще в пример не приводили, фильтрование и пр. без проблем пишутся и в С, пусть там и будет аж на одну строчку больше для цикла

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

Потому что они ПОЛЕЗНЫ. Что я (и остальные) и пытаюсь тебе втолковать. В ряде случаев они позволяют сократить код, сделать его более читаемым и лаконичным. Или удобство программирования — это уже не критерий?

критерий конечно... Короче - что-бы делать анонимные функции? Так? Потому как без анонимных функций я больше никаких плюсов не наблюдаю. Но анонимные функции может и повышают лаконичность, однако понятнее код явно не делают.

Мне вот такое

read_data([&a](const char * data, size_t size) { a.data_appeared(data,size); }); // nowait is here
не очень-то и понятно, если честно... Мне более понятной была-бы функция read_data которая принимает указатель на метод класса A.

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

Мне более понятной была-бы функция read_data которая принимает указатель на метод класса A.

Если у тебя 10 классов с 10 разными функциями с разными аргументами, то ты будешь делать 100 функций read_data или горидить огород с наследованиями и 100 отнаследованными классами-потомками?

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

Этот код — просто маленький пример того, какие приемущества дает использование лямбд по сравнению с их неиспользованием. То, что там «нет лямбд» может быть верным или неверным в зависимости от контекста. Например: в пхп есть лямбды и предача функционального аргумента есть одно свойств из лямбды -> этот код на пхп использует лямбды.

дык чем плох мой способ передачи функционального аргумента?

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

в качестве «функционального аргумента» ты _можешь_ передать 666. И одному Патрегу ведомо, как твой пхп это 666 разименует. А вот в мой код 666 ну никак не засунешь. Это конечно не идеал, но прострелить ногу в сишечке случайно не получится.

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

Это техника из 90х, которая неудобна, неэффективна, многословна, негибка. Сейчас за «указатель на метод класса» в приличном обществе вешают за яйца.

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

Ну а если мне надо частичное связывание сделать?

не знаю. может _в некоторых_ случаях в этом и есть смысл. Мне что-то такого не попадалось.

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

То есть, ненужность лямбд ты демонстрируешь на примере языка, где «функции имеют совсем иной смысл»? Одобряю!

ты немного не понял: в императивных ЯП не нужны лямбды. А в ФП лямбды конечно нужны, я и не спорил...

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

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

C++ уже давно мультипарадигмальный

Может _в некоторых_ случаях в этом и есть смысл.

Если ты пишешь helloworld, то смысл да нет, а в больших проектах это позволяет сильно сократить объем кода.

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

ты немного не понял: в императивных ЯП не нужны лямбды

Тебе - не нужны, потому что ты не понимаешь, что это такое и как им пользоваться.

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

Прикольно. Только это не аналог приведенного выше примера. Аналогом было бы что-то подобное:

typedef int (*UNARY_FUNC)(int);

UNARY_FUNC make_adder(int a)
{
    int adder(int b)
    {
        return a + b;
    }
    return adder;
}

/* ... */

UNARY_FUNC add5 = make_adder(5);

printf("%d\n",  add5(3));

Но это работать не будет, т.к. вложенные функции в GNU C не являются замыканиями. Т.е. при возврате вложенной функции из функции make_adder контекст, на который она замыкается, становится невалидным.

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

Если у тебя 10 классов с 10 разными функциями с разными аргументами, то ты будешь делать 100 функций read_data или горидить огород с наследованиями и 100 отнаследованными классами-потомками?

ну вот это есть: http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B Оно?

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

я сразу это написал, если что

А в чем твой пойнт? Понятно, что Си можно расширить так, что он будет поддерживать и лямбды, и замыкания.

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

И как это спасет от нагромождения ненужного кода, который только и делает, что пересылает данные от одной сущности другой?

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

Как до тебя всё туго доходит. Где аналог вот этого ?

def f(x): return lambda y: x+y

тут функция возвращает другую функцию (x+y). В сишечке так конечно нельзя, но вот вернуть указатель на функцию - можно. А указатель на функцию годен для использования как функции. Чем ты недоволен? фактически у меня ptr op() описывает функцию, возвращающую объект типа ptr, и потом можно писать f(x,y), где f - функция, которая вернулась из op().

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

C++ уже давно мультипарадигмальный

ФП там сделано через жопу. Это конечно не говорит о черезжопности самого ФП.

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

В сишечке так конечно нельзя, но вот вернуть указатель на функцию - можно.

Замечательно, давай код с возвратом указателя на функцию.

Чем ты недоволен?

Тем, что у тебя код делает совершенно не то, что в примере на питоне. В частности, на питоне возвращается функция от одного аргумента, а у тебя - от двух.

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

Но это работать не будет, т.к. вложенные функции в GNU C не являются замыканиями.

не будет. А почему функция должна быть обязательно вложенной?

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

дык объясни.

Пока что все объяснения тебе выливаются в твое «не нужно» и «я б вас, пэонэров, вешал за яйца». Ты либо искренне тупой, либо тролль.

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

ок, в пхп (задолбал меня этот пример) нужны или нет? а он ФП или нет?

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