Как стать автором
Обновить

Комментарии 83

Во многих функциональных языках, в частности в F#, существует так называемое внедрение типов: когда вы не задаете напрямую тип ваших данных, а компилятор, в зависимости о того как вы их используете, сам определяет что подставить.

Если не ошибаюсь, это обычно называют выводом типов (type inference).
Спасибо за поправку. Я не знал. Долго думал, как же это перевести, остановился на «внедрении».
Оу. Я почему то думал это оригинальный текст на русском и замечание оставил что бы уточнить сопоставимость терминов. Мало ли, вдруг что то новое.
Так это и есть оригинальный текст, мы беседовали по-русски.

Так зачем тогда переводить? )

Похоже пора расчехлить свой pet project на F#. Спасибо за интервью, вдохновляет шагнуть в функциональное программирование.

Я правильно понял, что на данный момент из реально завершенных «фунциональных» проектов у автора только «Жизнь» размером в 14 строк?
Вы до конца дочитали?

Небольшой группой последние полтора года на F# с помощью Akka.Net мы пишем систему, которая имеет высокие требования к быстродействию и масштабированию. Эта система разрабатывается для норвежского государственного радио-телевидения. Она оперирует многими сотнями терабайт файлов, работая с облаком. Код получается очень компактный, несмотря на сложность системы.
из реально завершенных «фунциональных» проектов

последние полтора года на F# с помощью Akka.Net мы пишем систему

Пишут, а значит пока не написали, а значит, согласно статье, у автора нет законченных проектов на функциональных языках, кроме игры «Жизнь».

Пишут, а значит пока не написали

Выходит, у Торвальдса, например, тоже нет законченных крупных проектов на Си.

Это значит написали, работет и продолжают развивать. Вот ссылка на доклад Вагифа "Опыт внедрения актёров на F#"
https://www.youtube.com/watch?v=wRxO5ky7S8g

Наверное это скорее акторы, а не актёры.
Конечно дочитал. Сам факт того, что они полтора года что-то пишут, ни о чем не говорит. Без демонстрации доведенных до ума продуктов все звучит жутко неубедительно.
Спасибо за интересный вопрос :-) Нет, вы неправильно поняли. На проект на F# для норвежского телевидения уже скоро год как в продакшн, сейчас готовится вторая фаза. Считать ли такой проект завершенным — это уже вопрос точки зрения. Но это 100% функциональный проект, который заставил многое пересмотреть. Основная причина, по которой в этой беседе я ссылался на довольно простую программу — при всей ее простоте на ней очень многое вскрывается, по крайней мере вскрылось для меня. К тому же она всем знакома. Ну и к тому же когда принимаешь для себя решение осваивать новую парадигму, то по определению нет завершенных проектов, надо на основании ограниченного опыта решать, в какую сторону двигаться.

Нет, вы поняли неправильно.

Вначале я пытался с этим бороться и писал также много тестов, как на C#. Потом я понял, что в этом нет необходимости, так как большинство логических ошибок отлавливается компилятором, который гораздо менее «прощающий», чем компиляторы объектно-ориентированных языков.

с чего это? компилятор знает как бизнес логика работает?
Многое ловится, если использовать discriminated union, особенно если включить опцию warnings as errors. Это вообще очень полезная категория типов для описания предметной области. Очень помогает и что тип record требует задания значений всех полей при декларации данных. Нет нулей, на NullReferenceException наталкиваешься лишь когда принимаешь данные из C#. И еще что существенно сказывается — нет никаких переменных, стараешься писать все в виде функциональных трансформаций, получается меньше, так сказать, движущихся частей.

При этом я мгного лет был в каком-то смысле TDD-junkie, старался писать тест на все что угодно.
Мне казалось, что я уже много подобных статей прочитал. Но впервые, я увидел для себя реальные причины начать изучать F#. То ли в этой статье написали что-то, чего не было в других, то ли в других было не так понятно.
Если вы посмотрите на объектно-ориентированный код, там будут какие-то переменные, какие-то данные, потом их куда-то посылают, и ко всему этому осуществляется доступ из многих потоков.

По моему это не про ООП, а о том, как многие его неправильно используют. :)
Да, это не относится ни к ООП, ни к его использованию, это про императивный подход к программированию.
Я для себя взял за правило не слушать тех кто пытается тебя в чем-то убедить. Нормальный доктор никогда не скажет кушать только фрукты потому что они витамины. ООП там где оно нужно, это сила. ФП на своем месте — наверное тоже. Игры делают не на ооп и не на фп, а на нечто среднем. Так же личный опыт подсказывает что разные программы требуют разные подходы. Когда я пишу ui я радуюсь mvvm, когда сервер mvp, когда простую игру, я наслаждаюсь mvc, когда большую игру ecs, когда я пытаюсь связать части архитектуры, я просто тащусь от реактивных библиотек. То место где мне нужна иммутабельность, я использую иммутабельност.ь. Но так же я знаю что везде иммутабельность просто не нужна, а если пытаться использовать архитектуру не там где положено-парадигму, а лишь из-за того что это модно, то это начала серии статей о том что все это ужас.
Но самое непонятное мне, это то, что лично я бы не стал писать 20 лет на том что мне не нравится.
«Но самое непонятное мне, это то, что лично я бы не стал писать 20 лет на том что мне не нравится.»

Если из моих слов сложилось такое впечатление, значит я совсем туманно выражаюсь.
Если из моих слов сложилось такое впечатление, значит я совсем туманно выражаюсь.

нам смог ответить человек, открывший для себя преимущества функционального подхода после 20 лет ООП-разработки


Это разве не означает что 20лет Вы писали на убогом-неудобном и неправильном подходе?

И ещё вопрос — функциональные библиотеки которые Вы используете, так же не имеют переменных и не хранят состояние свойствах?
Нет, не означает, конечно. Я и сейчас немало пишу на C#, переходил на него с Си++ с удовольствием. Что же до чужих библиотек, то речь идет непосредственно о коде, который пишем мы сами, о его прочности, о пригодности к параллелизации. Сопровождать же нужно будет свой домашний код, а не другие библиотеки.

Если вы переживаете по поводу производительности и иммутабельности — в f# достаточно средств оптимизации и можно втыкать mutable и кусочки ООП туда, где вам нужно.


Когда я попробовал f#, посмотрев лекцию VagifAbilov об экторах, я понял, что ФП — это именно то, как я стремился писать программы. И если в ООП языках я иногда чувствовал сопротивление инструмента, то в случае с f# все "как ножом по маслу".


ФП сейчас конечно форсится жутко, но это не делает парадигму плохой.

Согласен с вами. Все парадигмы программирования уместны в некотором контексте. То же самое функциональное программирование основано на вполне императивных интерпретаторах. Императивный код отвечает за работу ThreadPool, за доставку сообщений, за синхронизацию очереди сообщений. И только поверх всего этого растёт функциональное параллельное программирование.

Адепты концепций высокого уровня любят высокомерно бросать «ну а если вам нужна производительность — можно подключить си библиотеку». Можно подумать пользователям не нужна производительность. Или что отдельная библиотека — это не часть программы. Существенная часть программы, написанная в другой парадигме. И это даже не наводит их ни на какие мысли. Слишком много развелось узкоспециализированных программистов, не только не способных построить с нуля всю программную систему, но даже не представляющих как она устроена. Отсюда и утверждения, что только их болото достойно внимания.

Опять же, можно подумать, что параллельное ФП по своей сути отличается от процедурного и магически решает все проблемы. Никакой магии нет. За гарантии работы программа платит скоростью работы. Параллельное программирование — это такая сложная тема не потому, что сложно написать корректную программу (хотя это тоже удаётся не всем), а потому что невероятно написать оптимизированную, но всё ещё корректную программу. Выкинуть все проверки и остановки, без которых можно обойтись, использовать разные виды локов с пониманием ньюансов их использования. Простота ФП параллелизма лежит в том, что вместо десятков разных параллельных примитивов, точное использование которых позволяет снизить издержки, у нас остаётся два-три железобетонных, и если твоя область применения порождает издержки, то тебе придётся их терпеть.

Вот как магически можно решить проблему общего состояния в игре? Каждый актор должен знать состояния всех соседей и поля боя в целом. Можно использовать локи, а можно копить кучу копий и обеспечивать синхронизацию этих копий. И никак нельзя облегчить задачу — объединить несколько мутаторов в общий логическую систему и разбить обновление этой системы на фазы, внутри некоторых из которых можно ослабить гарантии пареллельного доступа. Что-то наподобие идемпотентного оператора, только более сложное и в масштабах системы, а не отдельного кусочка данных.
НЛО прилетело и опубликовало эту надпись здесь
> Почему вы считаете, что это истинно всегда?

Потому что все низковисящие фрукты уже собрали. И уж точно это верно в случае так называемого параллельного функционального программирования

> Кто мешает это сделать достаточно умному компилятору?

Таких компилятов ещё не написали. И напишут не скоро.
Как там обстоит дело со скоростью например при работе с охрененно гигантскими матрицами? Ну там крутить-вертеть их туда-сюда, перемножать и т.д. и паралельно крутить мозгокрутные конечные автоматы, ну и так далее?
На счет F# не знаю, но в Haskell вроде как есть возможность подключать высокопроизводительный код на c++. Аналогичную черную магию практикует питон. Из тех бенчмарков что я видел производительность хуже на 0-10%.
Так же есть так называемые «Небезопасные» функции для работы напрямую с памятью, думаю будет примерно то же самое.

P.s. Сам не имею опыта в таких вещах.
НЛО прилетело и опубликовало эту надпись здесь
Сразу оговорюсь, что опытом кручения гигантских матриц не обладаю, но судя по разным бенчмаркам, при особых требованиях к быстродействию F# уступит не только Си++, но и некоторые его модули (List, Map) проиграют по скорости структурам данных из .NET/C#. Если не ошибаюсь, Ayende (Oren Eni) делал сравнения, писал в своем блоге.
В более традиционных системах, однако, закон Амдала, указывающий на потери быстродействия залоченных данных, имхо, делает код с замками в многопоточной среде более уязвимым в плане быстродействия, чем функциональные алгоритмы без блокировки.

Так же не понятно, как реализовать кеширование без разделяемого состояния.
Отдельный кэш для каждого потока?
При обновлении кэша пересоздавать его заново?

Думаю, обобщенный ответ на этот вопрос лежит вне парадигмы программирования. Хотя в рамках некоторых моделей есть свои решения. Например, мы пользуемся моделей актеров — она доступна и из ООП, и из ФП, но поскольку актеры (или акторы, тоже не уверен, как лучше по-русски выразиться) не делят состояния, то по духу ФП ближе, не даром Akka пришла из Скалы. Так вот, в рамках этой модели у нас некоторые актеры хранят разделяемое состояние, доступ к котрому осуществляется путем обмена с ними сообщениями. Это может выглядеть тяжеловесно, позволяет полностью обходиться без замков.
— Что вы можете посоветовать тем, кто решил начать изучать функциональное программирование?

Вагиф Абилов: Посоветовал бы не относиться к этому выбору как к какому-то серьезному жизненному шагу. Я заметил, что пробовать изменить основной язык у программистов считается каким-то радикальным шагом в отличие, например, от смены базы данных или какого-то фреймворка. Например, разработчики на javascript меняют библиотеки, которыми они пользуются, как перчатки. И это не выглядит каким-то серьезным изменением. Если вы перешли с реляционной базы данных на document-базу, это во многом более серьезный шаг, чем перейти с одного .NET языка на другой.


Отлично сказано!

Вообще говоря, если ориентироваться на доминирующую архитектуру процессоров, то она императивна и мутабельна :)


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

В прошлом году Джо Армстронг (Erlang) делал доклад на NDC о принципах, заложенных в язык, и он как раз упирал на то, что в основе успеха Эрланга у телеоператоров и прочих систем, требующих масштабируемости и надежности — соответствие Эрланга (функционального языка) железу, на котором будут запускаться программы на нем. «We do not have ONE web-server handling 2 millions sessions. We have 2 million webservers handling one session each.» — сказал он же в другом месте. То есть несмотря на императивность и мутабельность архитектуры процессоров процессы на них имеет смысл запускать функциональные и неизменяемые.
НЛО прилетело и опубликовало эту надпись здесь

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

Так или иначе эти чистые функции изменяют состояние системы — ОЗУ и дисков, даже если про регистры не вспоминать. И делают это в императивной мутабельной манере, просто транслятор и(или) рантайм языка это скрывает.

Не стоит все доводить до крайнестей. Очеидно тут говорится об одном уровне абстракции, а вы опускаетесь на другой.
Третий важный аспект в реализации игры «Жизнь» на F# было то, что там я не ввел ни одного типа.

Это какое-то неправильное функциональное программирование. "Правильное" современное ФП обычно начинается с типов и управляется типами.

Это верное замечение, мне следовало лучше обговорить, что я имею в виду под важностью аспекта. ФП действительно управляется типами, но благодаря type inference их часто можно не вводить для промежуточных вычислений. Partial application тоже помогает на них не сосредоточиваться. Но ФП именно что начинается с типов — дальше они пускаются в плавание по трансформациями. ООП и начинается, и продолжается, и заканчивается типами, собственно парадигма такая, от нее не убежать. И это приводит к тому, что в реальной практике мы часто слишком многое определяем заранее, связывая свой дизайн.
> Первое, как я уже сказал, это отсутствие мутации данных — это очень важно.

Конечно важно. От этого асимптотика страдает. Частенько и коэффициенты при О-большом тоже.
Если честно, то немного не понимаю как функциональное программирование связано с быстродействием? (Пока вижу один плюс — простое распараллеливание участков кода — за счет отсутствия сайд эффектов) Насчет дизайна для меня очень спорно, наш мир не идеален, и работать в контексте персистентных структур очень сложно. Простой пример — работа с графами, мне сложно себе представить, как можно эффективно с точки зрения памяти и времени работы алгоритма работать с такими объектами (если учитывать, что это персистентная структура). Возможно императивный подход уже наложил сильный отпечаток, и это все предубеждения.
Как мне кажется, связь скорее всего связь отрицательная. Иммутабельность существующих объектов = постоянное создание новых, что врядли может положительно сказаться на производительности.

Если вы думаете, что нужно обязательно создать полную копию структуры (графа), чтобы внести небольшое изменение — вы ошибаетесь. Вот как-то так в двух словах. Совсем не хочу при этом сказать, что эти алгоритмы простые — скорее наоборот, они сложные (классическая книжка Окасаки — это просто идеальный способ сломать мозги). Но с точки зрения памяти и времени не все так мрачно.

НЛО прилетело и опубликовало эту надпись здесь
… а у меня на ассемблере около 70 строк занимает. Как можно на С# напилить больше я не понимаю, может там фреймворк какой? По ООП языкам в принципе Оккам плачет, может из-за этого.
НЛО прилетело и опубликовало эту надпись здесь
Ну вот возьмите async/await. Вроде бы это всего лишь синтактический сахар. Но реально уменьшает количество кода, а раз так, то и шанс сделать логическую ошибку. Я себя причисляю к той части программистов, которая чем больше пишет, тем больше ошибается, для таких, как я, компактность кода — это благо.
Если же брать примеры непосредственно из ФП, то какой-нибудь List.fold поначалу может и требует задуматься, что же там внутри происходит. Но пройдя через это и поняв, выходишь на иной уровень абстракции, выигрывая на нем в компактности.
Чем короче код тем проще его понять (при условии что это не просто переменные названы короче а сам алгоритм проще). В случае F# он проще за счет того что для того чтобы сделать одно и то же нужно как раз таки меньше логики описывать.

Сравните хелло ворлд хотя бы. На F# это одна строчка кода, на C# тебе и классы и полиморфизм, и аргументы из командной строки, и статик и синглтон — все в каше.
> (при условии что это не просто переменные названы короче а сам алгоритм проще).

> Сравните хелло ворлд хотя бы. На F# это одна строчка кода, на C# тебе и классы и полиморфизм, и аргументы из командной строки, и статик и синглтон — все в каше.

Так вы определитесь, алгоритм разный или строчки? Алгоритм-то hello world один и тот же во всех случаях.

Формально подходя, вроде к ФП понятие алгоритм в целом не применимо, алгоритм — описание шагов в определенном порядке, а ФП не задает порядок вычислений в функциях.

Вы преувеличиваете. Он не задается, если вычисление не зависит от результата другой функции. Тогда можно в любом порядке, параллельно и т.п. А иначе — извините, есть зависимость по данным, извольте соблюдать.

Порядок не задаётся программистом явно всё равно, он определяется по ходу дела в процессе определения того, что нужно сделать, чтобы получить результат по декларативным правилам заданным программистом. Программист пишет "чтобы получить результат функции A нужно применить такую-то трансформацию к результату функции B". Это правило не задаёт момент когда реально выполнится вычисление функции B, единственное что можно сказать, что вычисление функции A не закончится позже вычисления функции A, если результат необходим для этого вычисления. С натяжкой, конечно, можно назвать это порядком, но не в том смысле, в котором он используется в алгоритмах.

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

Функции в ФП мощнее тех, которыми пользуются в математике. Тут главное — функция выбора
IfThen( condition, trueValue, falseValue )

В математике, при комбинировании функций, значение функции не определено, пока не определены все аргументы. У функции IfThen в ФП фундаментальное отличие — если condition==true, то значение falseValue может быть не определено (а может и быть определено). На этом строится и рекурсия (условие выхода из рекурсии), отсюда и проблемы с вычислимостью (аналог проблемы остановки), это и даёт возможность записывать любые алгоритмы.
НЛО прилетело и опубликовало эту надпись здесь
Речь о том, что в ФП есть специальные функции, не вычисляющие все аргументы.
Работающие, как тернарный оператор (condition? value1 : value2) в C/C#.

Взять классический не ленивый LISP, с его функцией (cond) — там независимо от ленивости вычислена будет только одна ветка.
НЛО прилетело и опубликовало эту надпись здесь
Помните BASIC?
10 PRINT "Hello, World"

Тут helloworld так короткий, потому что BASIC — язык для начинающих (согласно расшифровке его аббревиатуры), т.е. язык для helloworld-ов. Дизайн языка говорит новичкам: смотрите, как просто — 1 строка и программа работает!

С другой стороны, если посмотреть на алгоритмы архивации, то доказано, что нет универсального — такого, который бы обошёл все алгоритмы на любых данных. Всегда найдётся лучше архиватор под специфические данные. С языками то же самое.
НЛО прилетело и опубликовало эту надпись здесь
А мне показалось убедительно, конечно не так, что бы все бросить и бежать, но серьезно изучить вопрос и начать осваивать — почему бы и нет? Спасибо за статью, правда хотелось бы больше примеров и сравнений, но можно и самому поискать

Вагиф, ФП очень даже востребовано в программировании интерфейсов, форм и прочего. Если вам интересен функциональный подход к написанию клиентских приложений, то очень интересный в этом плане язык — Elm http://elm-lang.org
Это, можно сказать, наследник Haskell для написания сложных frontend web-приложений, но при этом очень простой в освоении. Чистые функции, отсутствие null reference exceptions и вообще исключений в runtime для сложных SPA, где владычествует великий и ужасный js, — согласитесь, заманчиво

Да, точно. Спасибо за уточнение.
Вагиф, поясните, если «правильно» писать на ОПП — 1. Вместо мутабл — неизменяемое состояние
2. Вместо shared state — инкапсулировать состояние
и т.д…

То какие преимущества у ФП, кроме краткости, которое часто сомнительно?

Раскройте. за счет чего выше производительность при ФП, будет, если расход памяти больше на порядок (ведь состояние неизменяемое)? Как удается быстро освобождать неиспользуемую занятую память?
Влад, так в том-то и дело, что такой стиль написания на ОПП не считается однозначно правильным. Я согласен, что не надо очень напирать на краткость кода на ФП, это в конце концов не самоцель, хоть и полезно, но церемониальность многих языков ООП не связана с ООП как таковым, и при желании их тоже можно сделать более компактными. Вот здесь — набор слайдов, где предлагается синтакс языка C# Light, при использовании которого код становится сравнимым по компактности с фшарпом:

https://www.slideshare.net/ScottWlaschin/c-light

Но если брать другие, более важные моменты, то основная проблема языков ООП — это то, что они навсегда останутся языками мутирующих данных. Мы можем требовать от разработчиков команды высокой дисциплины, но нельзя заменить основы языка дисциплиной. Вот пересказ отзыва создателя Clojure Рич Хики о проблемах мутаций в ООП:

«It should also be obvious that OO languages have „no proper notion“ of values in this sense. As Rich Hickey points out, you can create a class whose instances are composed of immutable components, but there is no high-level concept of immutable value implemented as a first class construct within the class.

This is one of the main causes of headaches when doing OOP. How many times have you pulled your hair out trying to figure out how an object's attribute got changed? The fact is, in OO languages there is no built-in mechanism to ensure that the object you're dealing with is stable.

This is the big reason why concurrent programming is so difficult.»

Безусловно, современные C# и Java куда более пригодны для функционального стиля программирования, чем пятнадцать лет назад. Но такой стиль всегда будет оставаться для этих языков если не инородным, то по крайней мере не самым идиоматическим.
НЛО прилетело и опубликовало эту надпись здесь

D сиподобный и в нём есть неизменяемые структуры:


immutable struct Person {

    /// Full name
    string name;

    /// Birth day
    DateTime birthday;

}

auto person = Person( 'Alice' , DateTime( 2000 ) )
НЛО прилетело и опубликовало эту надпись здесь

Вообще говоря, автор c#light упростил лишь синтаксис для одного конкретного кейса — иммутабельные структуры, а для этого хватило бы обычных классических структур с модификатором. Тут не нужны классы, гетеры, модификаторы доступа и прочий высший пилотаж.

> Но если брать другие, более важные моменты, то основная проблема языков ООП — это то, что они навсегда останутся языками мутирующих данных

Так и компьютер — это механизм с мутирующими данными. И алгоритмы затачиваются именно под мутирующие данные. При переходе на немутирующие ленивые могут даже асимптотику потерять, доступную в императивном стиле.

Я как-то купился на всю эту чушь и попробовал пописать на хаскеле. Вроде даже получилось, хотя и геморно было. Но это я прак писал, никаких требований к производительности там не предъявлялось, лишь бы работало. Потом посмотрел, как большие мальчики пишут на хаскеле. Оказалось, что реальные либы включают монады памяти, IO, подключают сишный код. В общем, весьма далеки от идеалов чистоты. А иногда ещё и энергичные вычисления вместо ленивых используют, чтобы сборщик мусора не напрягать. Если кто не понял, то именно так и выглядит текущая абстракция. Когда сборщик мусора тормозит и нужно оптимизировать код не из соображений красоты и логичности, а чтобы мусор собирался.

> The fact is, in OO languages there is no built-in mechanism to ensure that the object you're dealing with is stable.

А как же константы? Очень удобная декларация, с самого начала программистам понравилась. Просто не надо все поля класс делать константными.

> Но такой стиль всегда будет оставаться для этих языков если не инородным, то по крайней мере не самым идиоматическим

Так он в любом случае будет императивным. Ну вот заменили все функции на структуры данных, запихали их во Free, получили ad-hoc синтаксическое дерево. Только вот оно само ничего не вычисляет. Его надо интерпретировать потом. И внезапно оказывается, что интерпретатор с большим энтузиазмом меняет состояния.
ребята
проблема не в том в какой парадигме суть языка программирования
а в том что суть языка есть Синтаксис
я до сих пор не могу понять Почему синтаксис все не вобрал в себе на Упрощения кода
пусть будет синтаксис совмещен от всех парадигм и от ООП и от Функций и от Прологов и всех остальных язычеств
программисту вообще нет дела до того как реализуются уже библиотеки и модули
ему есть дело Как решить ту или иную задачу за минимум времени чтобы получить максимум премию)
никто не хочет работать
так создайте Си шарп с синтаксисом Питона и Наскела))
столько не нужных скобок и типов которые в Айдле уже сами выставляются
упрощайте синтаксис и не хамите что это Сахарный десерт
и начинайте упрощать с ассемблера
и почему нельзя в ассемблере применять циклы)) по синтаксису — сами себе вы программисты хамите
вот что я думаю
Я вижу, вы и в русском языке синтаксис упростили — ни одной запятой
так прибавь по моде твердые знаки)) в конце слов русского языка чтобы тебе вторить)
если ты против упрощений то пиши все на ассемблере)) и забудь вообще другие языки
ведь можно в том тебя же укорить что Упростил себе жизнь используя любой другой язык а не ассемблер)
Пример с игрой Жизнь на F# не очень показательный. На C# с помощью linq получается примерно также:
        static void Main()
        {
            var rnd = new Random();
            var size = 10;
            var grid = Enumerable.Range(0, size * size).Select(_ => rnd.Next(2)).ToArray();
            Func<int, int, int> match = (v, n) => n == 3 ? 1 : n == 2 ? v : 0;
            var neighbours = new[] { -1 - size, -size, 1 - size, -1, 1, -1 + size, size, 1 + size };
            while (true)
            {
                Console.Clear();
                foreach (var s in Enumerable.Range(0, grid.Length / size)
                                    .Select(y => string.Join("", Enumerable.Range(0, size).Select(x => grid[y * size + x]))))
                    Console.WriteLine(s);
                grid = grid.Select((v, i) => match(v, neighbours.Sum(o => grid[Math.Abs(i + o) % grid.Length]))).ToArray();
                Thread.Sleep(300);
            }
        }

Переходя на LINQ, мы уже зачастую переходим на элементы функционального программирования. В вашем примере цепочка из Enumerable.Range -> Select -> Select — это ли не функцинальные трансформации? Обратите еще внимание, что вы решаете задачу для доски конечного размера, в то время как игра Конвея предполагает бесконечную доску (решение на фшарпе, о котором я говорил, не ограничивает размер доски).
Зарегистрируйтесь на Хабре, чтобы оставить комментарий