ФП ж не позиціонується як щось нішеве?
Ні. А треба? ;)
Фактично як раз воно близько до нішевого, і це не зовсім адекватно його корисності.
Доречі. Яка з функціональних мови найбільш широковживана? тобто використовується у реальних проектах у найбільшому числі різних областей?
Моя власна думка: LISP в усіх варіантах. Другим Erlang (включаючи Elixir). Третім OCaml.
А тепер дивимось на поточний TIOBE (так собі критерій, але щось відображає): 21 — LISP. 30 — Haskell. 31 — Scala. 48 — Elixir. 49 — ML (все сімейство). 50 — Clojure (можна вважати дуже специфічним варіантом LISP). Erlang, F# після них в
У мене це автоматизація чи обробка даних на Linux/Mac. Що порекомендуєту з вашого досвіду?
Не знаючи характер даних і методи обробки... нічого.
Ну тут ви скоріше підтвердили моє твердження про те, що як тільки ми підходимо до ФП — якась частина людей перестає розуміти.
А я не кажу, що це не так. Я кажу, що це вже наслідок того, що вчать, по більшости, у імперативному стилі. Після цього перемкнутись складніше і, типово, ліньки.
Навпаки для математиків більш інтуїтивним повинно бути якраз ФП.
Саме так. (Згадуючи деякі спілкування з «чистими» математиками...)
Я ще чудово пам’ятаю книжки з програмування, де описувався виключно процедурний підхід, без ООП, наприклад.
ООП менше відрізняється, ніж функціональний підхід. Де там є складнощі, вони не в головному принципу.
Тобто якісь речі, підходи, шаблони і паттерни стають мейнстримом, а якісь — ні.Чому?
Десь знайшовся той, хто перебʼє інерцію — зазвичай, бо є грошова віддача. А десь — ні. З ФП гроші дуже локалізовані, не можуть перебити весь світ програмування. Ну і підложка у вигляді сучасних компʼютерів таки заважає.
Я навіть більше прикладів покажу. Он є така штука kdb+. Пошукайте програми для неї. І краще на k, ніж на q (це її вбудовані мови такі). Це гірше ніж ФП. Але аналітика великих банків сидить на ній, і платять шалені гроші за ліцензії — коли воно ще було не почасово, було 50k$ за процесор. Я на ній дещо писав, більш не хочу:) але вражень набрався. Чи треба їм розповсюджувати на всіх? Думаю, ні. (Але можуть — знаю людей, які створили схожі униіверсальні аналоги.)
Вже 30 рочків, як це є. За 30 рочків багато чого стало мейнстримом, на що раніше не вистачало ресурсів.Чому про динамічні мови кажуть «та просто візьмемо потужніше залізо» — а ФП це досі обмежує?
Ось тут саме та інерція, про яку кажу. Нема невідʼємного обмеження динамікою. Зараз у Haskell, Ocaml, інших дуже гарні компілятори. Є обмеження традиціями і налагодженим конвеєром освіти і праці.
В Rust його спочатку треба самостійно написати під свою задачу. В Python я можу не паритись з типом, розібратися вже «по ходу».
Є готові. Посилань не накопичував, але бачив.
Я ніколи не писав у функціональному стилі і не писав на terraform до того, як почав працювати на проекті.
...
Я не знаю terraform. Може, це його проблема. Я 5 років писав на Erlang. Це легко, якщо вийти за шаблони процедурного мислення. У нас була група асушників-адмінів, яких вчили програмувати саме на ерлангу. Це було легко. Не було нічого на погляд тяжкішого, ніж звичайне навчання того, хто вже в IT, але не програмував.
Може, тут винен саме Terraform. Може, в ньому щось перемудрили. Я жодного рядку на ньому не бачив.
Ви могли б отримати достатній досвід для порівняння, якщо б писали хоча б в обʼємі півсотні задач якогось codingame, наприклад, на LISP (будь-якому діалекті, можна і Scheme, і CommonLisp, і Clojure) і Erlang. Або Erlang і Ocaml. Або LISP і Haskell. Тоді б ви могли сказати, проблема в Terraform одному чи в цілому в ФП.
SQL це ж теж не процедурний а декларативний підхід. Але якось я не бачу дописів — «я не розумію, що робить той запит».
Ви не бачили, я бачив. Особливо коли використовуються, наприклад, віконні функції. Ось це як раз близько до чистого ФП. Або конструкції з многорівневим вкладеним select і not in, там треба серйозно розгорнути в голові, щоб зрозуміти, що воно робить.
Але SQL дуже обмежена декларативна мова (за що його лають).
Звісно, що це суто мій особистий досвід, моя інформаційна бульбашка і я не маю якихось доказів чи об’єктивних вимірювань когнитивного навантаження від різних підходів.
Згоден. У мене теж, але саме з ФП у мене явно більше досвіду, як і з його порівнянням з ПП. Приклади, як люди успішно входять через ФП, показують, що не можна думати, що тільки ПП «інтуітивне» чи якось таке.
(Або ІП? Я весь час звав його процедурним, хоча багато хто зве імперативним. Може, останнє точніше.)
Те, що ви написали, звучить дуже страшно. Не прийняти людину за те, що вона захворіла? Не ok в сучасному світі.
Покинути за те, що захворіла, маючи довгу спільну історію — не ok. Не вибрати з самого початку, до серйозних відносин — ok. Ви вибираєте кожну першу зустрічну чи якісь маєте власні критерії?
У мене є знайома пара, де вона з діагностованою кліничною депресією зі складною історією і на сильних ліках. Є знайомі зі спадковими ментальними проблемами, теж сімейні. Але жити з такими — це власний вибір і постійний подвиг. Нікого не можна примушувати чи просто агітувати за таке. І соромити за відмову — теж.
Особливо це не ok в країнах Заходу, до яких ми так хочемо приєднатися і чиї цінності прагнемо перейняти.
А пропонуєте затикати собою амбразури у кращих радянських традиціях. «- Патроны кончились! — Но ты ж коммунист! — и пулемёт застрочил снова.»
Ну «пассключ» вже якось звучить. Спочатку буде незвично.
«Ключ-пароль» теж нормально. Але довше.
Функціональний підхід з’явився чи не в той же час, як і процедурний. Але поширення такого не мав. Чому?
Почнемо з того, функціональний підхід зʼявився раніше. Лямбда-зчислення народилось у 1920х і було доведено до розвиненої теорії у 1930х, коли ще жодного реального компʼютера не було.
Чому поширення такого не мав? Дуже просто. Компʼютер на найнижчому рівні працює процедурно. У нього є послідовність станів і переходи між станами. Коли був тільки асемблер, вчили процедурній роботі. Коли зʼявились перші мови вищого рівня, вони теж були процедурні, бо не вистачало ресурсів на ефективну трансформацію з функціональної побудови. Тоді навіть гарних оптимізуючих компіляторів не було, вони зʼявились ближче до 1990, а раніше найліпші робили код в рази повільніший за людину з асемблером.
І саме в цей період виникли всі основні мови и виникли традиції. Вибачте за міряння сивиною, але я почав в
Власне, лінія ML, Haskell і інших виникла тоді, коли побачили, що сучасні ресурси дозволяють компілювати програми на функціональних мовах в щось досить ефективне.
А традиції, в яких, звісно, процедурний стиль займав головне місце, вже склались.
А ось навпаки це чомусь викликає проблеми, бо «ломає звички» ;)
Я не мав досвіду в широкій масі з тим, що хтось навчився спочатку на LISP, а потім його пересадили на якийсь Python. Але є окремі знайомі, що скаржаться, що їм так незручно. І є група, яка вчилась майже з нуля програмуванню під Erlang, і їм легко зайшло. Так що не тільки навпаки.
Будь-який код все одно перетворюється на послідовність доволі простих операцій — немає процесорів, що працюють з функціональним чи процедурним кодом.
Нітъ! Процесор працює саме повністю і безперечно з процедурним кодом. Альтернативи тут немає.
Навіть якась LISP-машина, яких робили навіть серійно, просто має орієнтацію на конкретні структури даних і методи їх покрокової обробки.
І обирається той підхід, що вимагає від людей менше (когнитивних) зусиль.
Обирається той підхід, на який є люди і ресурси. І ось тут спрацьовує, що всі 80 активних років IT перевага була на боці процедурного підходу саме через його близкість до заліза. Його не просто використовують — йому, через те, вчать. А раз йому вчать — то він і далі розвивається більше, ніж альтернативи. Замкнене коло.
Уявіть, що вам треба обробити деякий масив даних.
А поясніть-но мені, до чого тут не мої слова? Ви вставили як цитату щось що я не писав.
Хоч і не мій приклад, але прокоментую:
Тобто значно більше когнитивне навантаження.
Якщо ви просто передаєте крізь себе дані, то навантаження однакове. Вам треба просто використати універсальний контейнер. Такі є і в Rust.
Якщо ви далі обробляєте дані в цьому ж коді, то вам треба зрозуміти, що робити з цими даними. І ось тут вистрілює те ж саме навантаження.
Я не бачу принципової різниці.
в принципі, той самий функціональний підхід, коли з однієї чи кількох вхідних структур даних отримуємо іншу структуру даних виконуючи послідовно якісь функції. І за моїм досвідом — це складно.
Чому складно? В чому саме різниця?
Поки що я не побачив нічого крім того, що просто звикли до покрокового виконання у процедурному стилі.
I.
Просто тому, що ФП має більшу когнитивну складність.
Ні, не має. Щонайменше, поки не звикнеш до процедурного стилю. А ось з процедурного вже переходити на функціональний складніше, бо ламає звички.
Тому я і кажу, що якісний програміст має знати хоча б основи одної мови ФП (LISP, Erlang...) і Forth, щоб побачити те ж саме з різних сторін. Тоді для будь-якого засобу розуміння буде вже кращим. (Не кажу про Prolog, це вже для джедаїв-первертнів. Але і він може бути на користь.)
Але для крудошльопства це таки не обовʼязково.
II. А ви взагалі побачили різницю між функціональною мовою і мовою з розвиненою системою типів, як в статті? Мені здається, що не побачили.
Звісно, з ФП простіше накласти на базовий рушій мови розвинену систему типів, бо в ній значно простіше забезпечити аналіз компілятором і відсутність сторонніх ефектів. Але і на процедурну мову це теж накладається з деякими ускладненнями.
Порівняйте у цьому аспекті хоча б C, Pascal і Ada. В Ada автовиводу типів, здається, немає, але ви можете легко обмежувати діапазони значень. Алгебраїчні типи на зразок {ok,Result}|{error,Error} теж можна, з ускладненнями. Це вже щось більш цікаве.
Зараз Rust дає схожі можливості, теж у процедурній парадигмі. І, здається, саме Rust у першу чергу буде тим, що покаже такі підходи до типізації головній масі програмістів.
Не памʼятаю, чи наводив я тут приклад. Функція заповнює масив до 4 значень і повертає кількість заповненого, або −1 якщо помилка, в int8_t. Функція, що її викликає, кладе результат в uint8_t, заповнює масив значень (дивом нічого не ломає) і передає по мережі. При помилці воно втискує 255 (бо −1) значень в масив на 4 комірки. Інший модуль приймає, десеріалізує і нарешті крешиться через переповнення в стеку і псування адреси повершення. Зрозуміло, що мова з AutoMM, як Java, C#, Python, Go, чи десятки інших, не дозволила б такий ефект. Але і щось рівня C, але з якісним контролем типів, просто не спонукала б на таке диверсійне використання одного значення...
А здавалось би стандартизоване обладнання!
Хто попрацював в розробнику такого обладнання, знає, що «стандартизоване» обладнання це у більшости випадків щось все одно прохиблене, а якщо вже виглядає згідно стандарту — то на самісінькій межі відповідности ;(
І вихід на крок за межі happy path, зазвичай, призводить до зламу сценарію і неочікуваним ефектам.
На жаль все саме так...
Passkey не обов’язково має бути фізичним.
Ага, ага. Ви нишком відредагували статтю:
За два роки, відтоді як паскейси (passkeys)
Ось цього «(passkeys)» не було. Але ви знову схибили: ніхто в здоровому глузді не буде передавати англійське key як «кейс» при наявности слова case. А разом з таємним редагуванням... «кращі» традиції пострадянської журналістики — невіглацтво і нахабство — на марші. Поточну версію я зберіг, на випадок, якщо ще раз таємно відредагуєте.
Після такого писати щось конструктивне про підняті питання якось не хочеться :crash:
За два роки, відтоді як паскейси були анонсовані та стали доступними для споживачів, FIDO Alliance нещодавно повідомила, що обізнаність про паскейси зросла на 50%, з 39% у 2022 році до 57% у 2024 році.
Passcase ще щось фізичне, типу такого.
Здається, журналіста знову хтось зґвалтував.
Ну я поки не бачив, скільки треба платити тому ШІ, щоб він виконував хоча б задачі рівня мідла 8×5x52 і з достатньої точністю. І щоб сам міг розробляти, тестити, деплоїти і все таке. Більше зарплати людини чи менше?
От тільки з практичної точки зору зазвичай якщо у нас немає пам’яті, то це із серії, що зникло живлення
А ось це вже диверсія — настільки закладатись на памʼять.
Так я не о проблеме останова :)
Так я и написал, что это аналогия.
Продолжаю удивляться, почему гопники такие агрессивные. Ах да, подождите...
Шаг 1: читаем, что проблема останова неразрешима в общем случае.
Шаг 2: пишем алгоритмы, которым конкретно (в смысле the particular algorithm) можно доказать все нужные свойства, включая конечность выполнения. Это несмотря на.
Шаг 3: убеждаемся, что компьютеры всё ещё работают, а не уходят в вечный цикл на каждое действие пользователя.
Если это и аналогия, то очень точная. Всё описать типами, может, и вредно для скорости написания. А вот защититься от наиболее типовых граблей, чтобы тебе не писало, что через NaN минут к тебе приедет [object Object] — это как раз то, для чего вообще придумали типизацию.
Ну це вже занадто;\
никто не не указал, что оно было слегка побито
А, может, потому и не понял.
Спасибо, с таким намёком видно — как тип уточняется «по месту» и неявно.
Это, конечно, очень простой пример. Я не уверен, что оно переносимо в ту обстановку, которую я описывал — там будет сильно сложнее вычислить такие вещи, компилятор может не потянуть. И не представляю себе, возможно ли вообще перепроектировать, чтобы он потянул;\
Но есть о чём думать.
або кричати щоб Oracle відмовилась від trademark на Javascript)
Краще перейменувати Javascript, щоб HRи не плутали більш з Java. Така назва з самого початку була некоректним трюком на збігу. Так що тут я за Oracle :)
В Erlang ещё тоже примерно так же можно.
Там будет слишком много заката солнца вручную. Если вы не перезапускаете на новом процессе с другими данными, то делать все эти выборы в коде... на gen_fsm нормально не укладывается, а иначе писать самому.
Или — «отказаться» от переменных как в ФЯ. Нет ссылок, нет проблем :)
Есть ссылки — а как иначе будут структуры данных реализовываться? — и есть проблемы. Если переносишь в фиксированное декларацией состояние — сам процесс переноса требует кода, и легко что-то потерять. Если оставляешь «там же» (насколько этот термин подходит) — могут быть недоинициализированные или лишние. Если какой-то прокси — ручная работа по его построению.
В одном из подкастов по Пайтон услышал что жалеют уже, что в Пайтон вставили номинативную. «Структурную надо было...»
Как по мне, ещё замороченнее было бы. А там уже жутковато.
Ні. Ми мислимо в подійно-керованому стилі. Що зараз найбільш важливе і термінове — те і робимо. А для планування створюємо залежності між подіями. Перш ніж вийти з дому — одягнутись. Перед цим — почистити зуби. Перед цим — поснідати. В проміжках між ними можна нагодувати кота, полити квіти, у них ніякої залежности з іншою підготовкою нема.
І цей весь стиль з залежностями — він як раз функціональний. А імперативний виникає, коли залежности вже укладені в якусь послідовність дій (часто — штучно, тому що реально неважливо, спочатку полити квіти чи почистити зуби, а коли є імперативна послідовність, це вже захардкоджено).
Тому що після того, як вас навчили складати дії в послідовності, ви вже почуваєтесь незвично, коли замість цього є тільки залежності результату, а виконання дій в строк якимось загадковим чином забезпечує рантайм чи компілятор.
А далі починаються ефекти, коли, наприклад, вже хтось лякається того, що в foo(bar(), baz()) невідомо в C/C++, в якому порядку bar() і baz() виконаються, і вони вимагають якусь Java, де цей порядок встановлено правилами мови. Їм некомфортно мати недовизначеність навіть в таких малих питаннях.
Не бачив конкретний випадок і не знаю, що саме там спричинило проблеми. Може, і щось інше. А, може, таки різниця в стилях. Це вже інше питання.