LINUX.ORG.RU
Форум — Talks  

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

 , ,


7

7

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

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

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

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

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

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

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

переносимости между чем и чем?

да хотя бы между диалектами, тот код, что я привел будет работать даже в С++, и будет работать даже, если б я там использовал glib, про аппаратные платформы и компиляторы самого С и говорить не стоит; в лиспе такого нет, шаг влево, шаг вправо - и разбирайся с особенностями диалекта, платформы, различиями в реализации CL, недоработками и «фишками», которые были взяты из Lisp Works, например, и не поддерживаются нигде больше, опять же - это не претензии, я прекрасно понимаю почему и зачем так получается, в С тоже не все гладко, повторюсь - я просто не считаю использование glib чем-то плохим для написания кода примера

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


Да я знаю где смотреть. Просто пример на С - самодостаточен, а в примере на lisp используются заранее написанные функции.

Это я не к тому, что lisp плохой, а к тому, что далеко не всё так радужно как выглядит :)

На сях тоже запросто можно написать что-то типа
reduce( «+», (take(m, fact(n+m)));
Но функциональщик тут же начнёт вопить «а распиши код reduce!!!». :)


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



Тяжело что-то ответить. Вы слишком не в теме. Лучше задавайте вопросы, а не рассуждайте и не делайте выводов.

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

Мимо. Все приведенные примеры на clojure переносимы и по-умолчанию будут компилиться и работать и под маком, и под линуксом, и под виндой. В отличии.

я тебе удивлю, но glib собирается и работает не только на маке, линуксе, венде, но и на многих других ОС и аппаратных платформах, твоему clojure такое и не снилось

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

я тебе удивлю, но glib собирается и работает не только на маке, линуксе, венде, но и на многих других ОС и аппаратных платформах, твоему clojure такое и не снилось

Это просто прекрасно. Я только рад этому факту.

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

Вы слишком не в теме.

Вот именно из-за такого сверхнадроченного ЧСВ любителей функциональщины lisp, увы, не является популярным языком. А мог бы. :)

Тащемта если бы не автокад с емаксом о lisp'е бы ваще мало кто знал, например.

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

«возвращаемая функция» - это новый код для процессора, которого не существовало в при старте программы ни в каком виде или всякая хренота типа указателей, как обычно?

Он новый, поскольку лежит по своему уникальному адресу, но каждый раз как замыкание аллоцируется по очередному новому адресу туда пишется один и тот же код (собственно, скомпилированный код замыкаемой лямбды или вложенной функции), то есть машинный код разных замыканий не отличается друг от друга (хотя в итоге у них разные адреса), отличается замыкаемый контекст (то есть все captured varibles) который связывается (тут могут быть разные техники, начиная с closures из glib и вплоть до поддержки в VM и компиляторе) с замыканием (почему оно называется «замыкание»).

По сути, замыкание это struct { closure_context_t closure_context; closure_fun closure_fun; } - можем при вызове closure_fun_t передать ей closure_context, или все captured varibles доставать по смещению (так как функция и контекст лежат рядом в памяти). Аллокация замыкания при этом это в точности как new для этой struct с копированием closure_fun и выставлением closure_context по месту создания (с копированием или по ссылке). Просто lambda это, считай, обычная вложенная функция с random_name которое должен выбрать компилятор, незамыкающая вложенная функция random_name эквивалентна глобальной функции random_name, замыкающая невозвращаемая вложенная функция random_name эквивалентна глобальной random_name с передачей ей замыкаемых переменных, наконец, возвращаемая замыкающая функция random_name это единственный случай когда глобальной функцией уже не обойтись и нужна настоящая аллокация кода замыкания со своим контекстом в куче.

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

Реализация непосредственно map - это те же 6 строк:
...
В C# есть делегаты, все операции где функции передаются как параметры или возвращаются как результат работы другой функции, оперируют делегатами
...
Func, Action - это просто предопределенные в библиотеке делегаты, для удобства. Во всех случаях где используются делегаты можно передавать любой метод с совпадающей сигнатурой.

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

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

Вопрос что именно в куче лежит - код получившийся (по замыслу) новой функции или же некий стандартный код для реализации нужного поведения который в итоге обращается к коду в 1002D942D9.

Ну если взять

(defun get-closure (x) (let ((z x)) (lambda (y) (incf z y) z)))
(defvar *first-closure* (get-closure 1))
(defvar *second-closure* (get-closure 2))
;; *first-closure* => #<CLOSURE (LAMBDA (Y)) {1002AE7AF9}>
;; * *second-closure* => #<CLOSURE (LAMBDA (Y)) {1002B48C29}>

то по 1002AE7AF9 лежит код lambda со связанным контекстом в котором z = 1, а по 1002B48C29 - тот же самый код, но уже другая копия и с другим контекстом в котором z = 2. Так что такие замыкания ведут себя как самостоятельные объекты.

но потенциальные возможности оной могли бы быть полезными

Нет таких. По крайней мере, это уже не относится к анонимным функциям и замыканиям.

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

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

Компилятор сам это делает. При использовании лямбд компилятор выводит типы где это возможно, при передаче метода никаких кастов и специализаций проводить не надо, передается только имя метода.

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

Хоть одна лямбда в каком-нибудь языке возвращает ли реально _функцию_?

Вопрос в каком языке не возвращает. Ну в си.

что «с Си»? В выражении

x = foo(y);
«foo» это по твоему ЧТО?

Или есть ЯП, в котором функция возвращает скомпиллированый набор байтов, который куда-то пишется и потом выполняется?

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

Большое спасибо за подробный и толковый ответ.

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

Кстати, отсюда следует, что лямбды нигде нынче не оптимизируются при вызове, т.е. вызов какой-нибудь абстрактной (define (myfunc f) (lambda(x) (f x x))) как ((myfunc -) 123) приведёт к тому, что процессор тупо будет из 123 вычитать 123 ?

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

замечательно, рад, что теперь у тебя нет претензий к использованию данной библиотеки

К библиотеке претензий нет. Претензии к реализации остались.

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

Всё понял, реальное спасибо ещё раз.

Блин, вот почему таких текстов и примеров нету в книжках про ФП? Всё ж просто и понятно становится. И понятно где уместно эту фичу языка применять, а где нет. И понятно почему. И ответ на собственно вопрос в топике становится очевиден.

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

да хотя бы между диалектами

С фига ли код должен быть переносим между двумя разными языками? Тем более, что этого никто не обещал.

я привел будет работать даже в С++

А в Яве будет? Как, нет?

которые были взяты из Lisp Works, например, и не поддерживаются нигде больше

А гнутые расширения гцц тоже не все компиляторы С поддерживают. Такие дела. Вне стандарта каждый извращается как хочет.

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

Написать можно хоть на ассемблере. Но если нет возможности реюзать код, расширять, упрощать, обобщать то это решение плохое.

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

сфига ли код должен быть переносим между двумя разными языками?

«Есть языковое семейство: Lisp. У него есть разные диалекты» (с) ugoday - вот так всегда, как хвалить лиспы - так это диалекты, а как спрашивают про различия - это совершенно разные ЯП

А в Яве будет? Как, нет?

а с каких пор ява диалект С? диалект С - это тот же GNU C, например

А гнутые расширения гцц тоже не все компиляторы С поддерживают.

зато написав код под С, я его могу собрать компилятором с «гнутыми расширениями», у вас же несовместимые «диалекты» - это норма жизни

Такие дела. Вне стандарта каждый извращается как хочет.

ага, только у С есть стандарт, причем тот, который все соблюдают (расширения сделаны отдельно и опционально)

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

нужна настоящая аллокация кода замыкания со своим контекстом в куче.

а как быть с разделением данных и кода во славу безопасности? большинство эксплоитов как раз и использует выполнение специально подготовленных «данных» как кода.

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

Но если нет возможности реюзать код, расширять, упрощать, обобщать то это решение плохое.

Вообще-то частенько проще написать 10 символов заново, чем вспоминать как называется та функция с этими 10 символами и какой там у неё порядок аргументов. Ну и затраты на накладные расходы при вызове такого могут быть больше чем затраты на саму функцию.

Разумеется, если символов 100, то уже имеет смысл озадачится.

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

что «с Си»?

Нет лямбд, вложенных функций и возвращаемых лямбд и вложенных функций? Если в gcc с nested functions сделать

typedef int(*fn)(int);

fn foo(int x)
{
    int bar(int y) {
        return x + y;
    }

    return bar;
}

то bar окажется на стеке, а тот по возвращении откатится и будет у нас мусор вместо указателя и мусор, segmentation fault или illegal hardware instruction при его вызове.

«foo» это по твоему ЧТО?

Какой-то ?(*)(...), то есть имя глобальной функции, глобальной или локальной переменной. А это тут при чём.

Или есть ЯП, в котором функция возвращает скомпиллированый набор байтов, который куда-то пишется и потом выполняется?

Есть ЯП в функциях которого можно сделать new и вернуть полученный объект. Если этот объект при этом callable то, ну, у нас будет замыкание :)

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

Но если нет возможности реюзать код, расширять, упрощать, обобщать то это решение плохое.

ты сам не знаешь чего хочешь, ну напишу я так, например:

int fact_count( int m ) {
    int c=0;
    for( ; fact(c+1)<m ; ++c ); 
    return c;
}

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

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

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

Вообще-то, фича того же lisp как раз в том, что данные и код это одно и то же - просто элементы списка ( то, что в скобочках - список ).

большинство эксплоитов как раз и использует выполнение специально подготовленных «данных» как кода.

Любую технологию можно использовать как во вред, так и во благо.

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

Вот именно из-за такого сверхнадроченного ЧСВ любителей функциональщины lisp, увы, не является популярным языком. А мог бы. :)
Тащемта если бы не автокад с емаксом о lisp'е бы ваще мало кто знал, например.

Троллинг троллинком, а вы поинтересуйтесь в интернете, где используется лисп, включая clojure.

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

Вообще-то частенько проще написать 10 символов заново, чем вспоминать как называется та функция с этими 10 символами и какой там у неё порядок аргументов. Ну и затраты на накладные расходы при вызове такого могут быть больше чем затраты на саму функцию.

В приведенных в данном треде сишниками примере больше 10-ти символов. Про какие затраты вы говорите? Препоны для реюза идут от языка или от ваших способностей?

З.Ы. Я понимаю, что вы троллите. Но тема достаточно интересная для самообразования. Еще раз советую, не судите, не делайте заявлений. Побольше спрашивайте, если непонятно. Спрашивать желательно конкретно, без собственных предположений.

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

это совершенно разные ЯП

Слово «совершенно» здесь лишнее. Языки похожие, близкие, но разные.

а с каких пор ява диалект С?

Ну. Они же похожи. Почти как КЛ и кложура. :-)

зато написав код под С, я его могу собрать компилятором с «гнутыми расширениями»

Гцц может собирать код _без_ гнусных расширений. Это безусловно хорошо.

Точно так же ты можешь рабоать в SBCL со стандартным КЛ кодом. Здесь абсолютно симметричная ситуация.

у С есть стандарт

Вот, можно подумать ANSI CL или схемовский RxRS это не точно такие же стандарты.

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

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

Код всё равно использует данные. Вот есть функция F, в её коде используются переданные ей аргументы, если мы позволим возвращать из этой функции F другие локальные (определённые _внутри_ её тела) функции G_i, то они должны неизменно утаскивать с собой свой контекст вычисления, то есть, если несколько раз вызвать функцию F, то все полученные функции G_i должны быть независимы. F тут ведёт себя подобно конструктору класса с new, а G_i как объекты этого класса на которых можно вызывать его методы (замыкающие и использующие его данные).

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

большинство эксплоитов как раз и использует выполнение специально подготовленных «данных» как кода.

Я думаю, написать эксплоит к old school style сишной программе гораздо проще, чем ломать этими old school методами какую-нибудь толстую VM вроде JVM, интерпретатор или даже современный плюсовый рантайм.

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

Троллинг троллинком, а вы поинтересуйтесь в интернете, где используется лисп, включая clojure.

Мне достаточно знать где лисп не используется, и что он не используется массово, хотя мог бы.

Ну и мне в конце-концов просто обидно, что неплохой, в общем-то, язычок не является таким же swiss army knife из стандартного комплекта как С, perl, sh и теперь уже наверно python.

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

ты сам не знаешь чего хочешь, ну напишу я так, например:

int fact_count( int m ) {
    int c=0;
    for( ; fact(c+1)<m ; ++c ); 
    return c;
}

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

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

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

а с каких пор ява диалект С?

Ну. Они же похожи. Почти как КЛ и кложура. :-)

Может, они принадлежат одному семейству?

Вот, можно подумать ANSI CL или схемовский RxRS это не точно такие же стандарты.

Не точно. Это стандарты разных языков. Кстати, несовместимых (Lisp 2 и Lisp 1).

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

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

а ты присмотрись, разве ты видишь в функции fact_count вычисление факториалов? или ты считаешь, что тут уместно было использовать другую функцию? внимательно слушаю

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

Может, они принадлежат одному семейству?

Это уже спор о словах. Можно конечно начать длинную <del>болтовню</del> дискуссию на предмет сколько отличий образуют диалект, а со скольки начинается уже новый язык, но толку от этого никакого не будет.

Сейчас я просто констатирую, что Clojure и CL это два разных языка, код между которыми (за исключением совсем тривиальных случаев) не переносим. Эту переносимость никто не обещал, к ней никто не стремился и ожидать её не нужно.

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

В приведенных в данном треде сишниками примере больше 10-ти символов.

Эмм... for(y=1;x;x--) y*=x; - это 20 символов. Пишутся за несколько секунд из головы. Это что, настолько принципиально чтоб прям 10 символов и ни символом больше?

Про какие затраты вы говорите? Препоны для реюза идут от языка или от ваших способностей?

От особенностей работы процессора и способностей компилятора. Знаете ли, вызов и возврат из функции может выливаться в десятки команд процессора. Если само тело функции, её полезная часть состоит из 10 выполняемых команд - накой нужно каждый раз ещё 10 ненужных инструкций выполнять?

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

я просто констатирую, что Clojure и CL это два разных языка

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

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

Только не bar, а x и y.

Я про trampoline который возвращает foo - он на стеке и по нему происходит вызов

    int x = 0;
    printf("%p near %p\n", &x, foo(0)); // => 0x7fffde04c7bc near 0x7fffde04c784

поэтому может быть illegal hardware instruction.

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

Property - это свойства, такой гибрид поля с методом.

using System;

namespace test
{
	public class Test
	{
		public Test ()
		{
		}

		// автоматическое поле
		public int Property1 { get; private set; }

		// явное определение
		private int _property2;
		public int Property2 { 
			get {
				return _property2;
			}
			private set {
				_property2 = value;
			}
		}
	}
}
Свойства разворачиваются в приватное поле и 2 метода для set и get.

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

Нет лямбд, вложенных функций и возвращаемых лямбд и вложенных функций?

нет. Вопрос нужны-ли они?

«foo» это по твоему ЧТО?

Какой-то ?(*)(...), то есть имя глобальной функции, глобальной или локальной переменной. А это тут при чём.

при том, что синтаксически foo(x) выглядит одинаково, без разницы, что такое foo - функтор или имя функции. Потому я не вижу никаких препятствий в написании точно такого же кода, как в фунциональных ЯП, если это необходимо. Пример выше я уже приводил - если мне нужно вернуть функцию, я возвращаю указатель на функцию. Требование, что-бы код лежал обязательно на стеке, и туда копировался каждый раз, мне кажется избыточным. Профиты такого решения, ИМХО намного меньше потерь (потери например из-за самого копирования кода в область того же стека. К тому же, насколько мне известно, в ФП этим невозможно управлять на уровне ФП - что-бы я не написал, компилятор всё равно будет (не)пихать мой код в область стека, даже если мне оно не надо). Сишечка в этом плане намного гибче, ибо данные я могу помещать там, где это мне нужно, а не там, где захочется компилятору.

Есть ЯП в функциях которого можно сделать new и вернуть полученный объект. Если этот объект при этом callable то, ну, у нас будет замыкание :)

в сишечке есть указатель на функцию, который вполне себе callable. Он замкнут на параметры функции, а в качестве параметра ты можешь использовать не только объект, но и указатель на объект, получая таким образом замыкание. Т.е. твой пример можно переписать так:

/* функция замыкания, вычисляющая квадрат переменной на которую она "замкнута" */
void squ(int *x)
{
    *x *= *x;
}

typedef void (*ptr_fun)(int*);// описание указателя

ptr_fun foo=squ;// создание "лямбда-функции"

{
    y = 12;// локальная переменная
    foo(&y); // замыкание на локальную переменную в этом контексте
}

вот чем тебе это не нравится?

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

Мне достаточно знать где лисп не используется, и что он не используется массово, хотя мог бы.

Зачем его использовать массово? Это же не пэхэпэ какой-то.

Ну и мне в конце-концов просто обидно, что неплохой, в общем-то, язычок не является таким же swiss army knife из стандартного комплекта как С, perl, sh и теперь уже наверно python.

Все смешалось: люди, кони.

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

откуда такая мания выносить каждые две строки в функцию?

это ФУНКЦИОНАЛЬНОЕ программирование.

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

а ты присмотрись, разве ты видишь в функции fact_count вычисление факториалов? или ты считаешь, что тут уместно было использовать другую функцию? внимательно слушаю

Я получил от тебя код. Оценил его, как не реюзабельный. Привел свой вариант. Если тебе нужна еще одна попытка, то не стесняйся.

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

Вообще-то, фича того же lisp как раз в том, что данные и код это одно и то же - просто элементы списка ( то, что в скобочках - список ).

я в курсе...

Любую технологию можно использовать как во вред, так и во благо.

потому-то я и говорю, что ФП более уязвимо в общем, сферическом случае.

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

Про какие затраты вы говорите? Препоны для реюза идут от языка или от ваших способностей?

От особенностей работы процессора и способностей компилятора.

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

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

Я получил от тебя код. Оценил его, как не реюзабельный

когда кончаются все придирки - остается только одно: пороть чушь без всяких аргументов и обоснований

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

Блин, вот почему таких текстов и примеров нету в книжках про ФП?

В SICP про statefull замыкания есть, тут (gigamonkeys.com) есть, и тут (bookshelf.jp) тоже. Хотя это немного лисповая фича, поэтому книжки про лисп. В книгах про чистое ФП или лямбда исчисление никто не будет рассказывать про let over lambda с мутабельностью, но так как большинство языков не чистые, то всё равно приходится делать замыкания с состоянием, так что подобные примеры будут работать.

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

Зачем его использовать массово? Это же не пэхэпэ какой-то.

Если вещь хороша и полезна - почему бы её не использовать массово? Чо за элитаризм такой?

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

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

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

Т.е. вам писать хороший код мешает язык программирования?

Вы когда говорите «хороший код» - вы что имеете ввиду?

Код хороший должен быть для кого?

Тяжело наверно так страдать или уже привыкли?

Я ваще ни разу не страдаю. Для меня код хорош если он делает то, что нужно, работает максимально быстро и жрёт минимум памяти. Это хороший, годный код. И такой код я пишу без какого-либо напряжения. Это, в общем-то, даже является для меня хорошей развлекухой.

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

потому-то я и говорю, что ФП более уязвимо в общем, сферическом случае.

Будет конкретный пример? Или так, фантазии?

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