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 замыкания есть, тут есть, и тут тоже. Хотя это немного лисповая фича, поэтому книжки про лисп. В книгах про чистое ФП или лямбда исчисление никто не будет рассказывать про let over lambda с мутабельностью, но так как большинство языков не чистые, то всё равно приходится делать замыкания с состоянием, так что подобные примеры будут работать.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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