Функціональне програмування — з чого почати

Доброго дня і з Новим Роком, шановна спільнота!

Після останніх статтей Dmitry Astapov у мене з’явилося трохи більше мотивації взятися за ще одну мову, і спробувати таки писати у функціональній парадигмі. Всі питання мені хотілось задати тут, реальним фахівцям. Але вирішив спочатку пошукати самостійно.

Якщо у вас виникне питання «Щоб що?» — то just for fun! Ну і мізки розім’яти...

Заодно вирішив ще раз потестити ШІ, задовбавши його запитаннями — тож майже вся інформація надана Google Gemini 2.0 Flash Experimental та Copilot. Саме так і треба сприймати цю статтю — одночасно огляд мов програмування та порівняння ШІ.

В принципі, зі вступом закінчено, але ще один момент хочу зауважити. Я був трохи здивований тим, що Copilot впорався, як на мене, значно гірше, хоча запитання були одні і ті ж. Запитань було багато, і наводити повний лог запитань та відповідей не буду щоб не гаяти ваш час. В принципі, можете повторити мій досвід самостійно. А здивований я був тому, що я вже порівнював ці дві моделі в робочих питаннях — terraform/python і зазвичай Copilot давав кращі відповіді (Gemini навіть якось відмовляв мене від використання одного провайдера terraform на користь іншого, мовляв другий стабільніший і поширеніший :D). До речі, Gemini дає приблизно однакові відповіді на запитання англійською та українською, а ось Copilot краще розуміє англійську (навіть мою, хе-хе)

Я впевнений, що вчити щось краще на реальних задачах. І якщо вже щось вчити — то вчити щось корисне, що можна використовувати в своїй кожнодневній роботи, чи, хоча-б, у пет-проекті. Це було основне припущення.

Перше питання було — надати перелік функціональних мов програмування:

— Gemini: Haskell, Scala, Erlang/Elixir, F#, Clojure, OCaml, Lisp
— Copilot: Python, JavaScript, Scala, F#, Haskell, Erlang, Clojure

тут судіть самі. Як на мене, відповідь Gemini коректніша.

Наступне питання — охарактеризувати ці мови з точки зору складності вивчення, галузей застосування і чи можна створити бінарник, щоб просто використовувати його не маючи всієї інфраструктури для копміляції коду на цільовій машині.

Відповідь Gemini:

Мова          Компіляція  Сфери застосування                                  Поріг входу
Haskell       Так         Фінанси, аерокосмічна галузь,
                          верифікація, компілятори                            Високий
Scala         Так (JVM)   Веб-розробка, великі дані, фінанси                  Середній-високий
Erlang/Elixir Так (BEAM)  Телеком, месенджери,
                          системи з високою паралельністю та відмовостійкістю Середній
F#            Так (.NET)  Фінанси, веб-розробка, аналіз даних                 Середній
Clojure       Так (JVM)   Веб-розробка, фінанси, обробка даних                Середній
OCaml         Так         Розробка компіляторів, системи верифікації,
                          фінанси, академічні дослідження                     Середній-високий
Lisp          Так         Штучний інтелект, автоматизація,
                          аерокосмічна галузь, графіка,
                          макроси та метапрограмування                        Середній

Щось мені підказує, що питання про компіляцію не зрозуміла жодна з моделей, хоча я перепитував кілька разів українською та англійською — обидві моделі надали відповідь, що «Так». Схоже що обидві моделі розуміють це питання як «чи принципово можливо отримати бінарнік». І зовсім не розуміють контексту — наскільки це вживано, просто і стабільно працює для будь-якого коду не відповідній мові.

В принципі, для перерахованих мов відповідь Copilot дуже схожа, додам тільки про Python та JavaScript (хоча далі їх розглядати не буду)

Мова       Компіляція Сфери застосування                                  Поріг входу
Python     Так        Data science, web development, automation, finance. Низький
JavaScript Так        Web development, mobile app development, 
                      server-side scripting.                              Низький-середній

Наступне запитання було про те, з якої мови краще почати, якщо я хочу поглибити свої навички програмування саму у функціональному стилі.

Gemini рекомендує F# | Clojure
Copilot — Haskell | Clojure

Але-ж мене цікавлять суто практичні питання застосування, тому далі я питав про пошук роботи програмістом на ціх мовах. З розділенням по регіонах:

Всі моделі стверджують, що в Європі більш поширені Scala та Haskell, а в США — Clojure та Haskell. Copilot ще додав, що в Азії поширений F# - цікаво, чому?

А ось google trends показує, що найпоширеніші — Scala, Haskell, Elixir, F# (Саме в такому порядку)

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

«Я працюю зазвичай з Linux та MacOS. Мої повсякденні задачі — це автоматизація системного адміністрування, DevOps та обробка даних, наприклад парсінг xml/json/yaml/csv або виводу консольних програм чи веб сторінок і видача оброблених даних в якомусь з перелічених форматів або запуск сторонніх програм за результатами отриманих даних»

Звісно, що обидві моделі написали мені, що Python — найкращій вибір для мене. Але ж то не цікаво, бо я і так його використовую, давайте щось нове :D

Gemini — Elixir | Haskell
Copilot — Clojure (і тут Остапа понесло — хоча я просив рекомендувати щось з вищеперерахованих, модель почала рекомендувати та описувати переваги Bash/Go/JavaScript)

Доречі, видавати щось, про що я не питав — прям фішка Copilot, інколи це гарно, а інколи — навпаки. В загальному випадку, краще-б не надавала зайвого шуму.

Ну і порівняння синтаксису, куди ж без цього:

Python:

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(5))  # Виведе 120

Haskell:

factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)

main :: IO ()
main = print (factorial 5) -- Виведе 120

Scala:

object Factorial {
  def factorial(n: Int): Int = {
    if (n == 0) 1
    else n * factorial(n - 1)
  }

  def main(args: Array[String]): Unit = {
    println(factorial(5)) // Виведе 120
  }
}

Erlang:

-module(factorial).
-export([factorial/1, main/0]).

factorial(0) -> 1;
factorial(N) when N > 0 -> N * factorial(N - 1).

main() ->
  io:format("~w~n", [factorial(5)]). % Виведе 120

Elixir:

defmodule Factorial do
  def factorial(0), do: 1
  def factorial(n), do: n * factorial(n - 1)
end

IO.puts(Factorial.factorial(5)) # Виведе 120

F#:

let rec factorial n =
    match n with
    | 0 -> 1
    | n -> n * factorial (n - 1)

printfn "%i" (factorial 5) // Виведе 120

Clojure:

(defn factorial [n]
  (if (zero? n)
    1
    (* n (factorial (dec n)))))

(println (factorial 5)) ; Виведе 120

OCaml:

let rec factorial n =
  if n = 0 then 1
  else n * factorial (n - 1);;

print_int (factorial 5);; (* Виведе 120 *)
print_newline ();;

Lisp (Common Lisp):

(defun factorial (n)
  (if (zerop n)
      1
      (* n (factorial (- n 1)))))

(print (factorial 5)) ; Виведе 120

Але подивившись на документацію всіх цих мов глибше, у мене склалося враження, що почати, якщо важливіше саме практика, краще зі Scala — а якщо на перше місце поставити теоретичні/академічні питання то Elixir | Haskell

Цікаво було-б почути рекомендації від людей з досвідом. Можливо вся ця інформація і ваші коментарі допоможуть комусь зробити вибір — з чого почати.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось4
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Починати краще з Clojure, потім OCaml. Опціонально Haskell. Для роботи F# чи Scala, або Erlang/Elixir.

З коментарів я вже майже впевнився, що почну з Haskell, навіть на десктоп та мак вже встановив. Та й книжок накачав на читалку.

Дякую за відповідь. А чому саме в такому порядку?

Haskell буде сприйматись як магія без загального бачення, багато розрізнених концепцій.
Clojure бо максимально простий синтаксис й нема статичної типізації. OCaml (чи взагалі SML) бо це по суті типізований Lisp, без лінивого обчислення, чистоти, ad-hoc поліморфізма та higher-kinded типів: набагато простіше за Haskell, багато що треба писати ручками, але достатньо потужний та елегантний, щоб це давало усвідомлення і інтуіцію, які можна потім перенести на Haskell, Scala чи F#.

OCaml дозволяє багато речей писати максимально прямолінійно, в той час як у Haskell потрібні нетрівіальні зусилля щоб закодувати бажані абстракції з бажаною гнучкістю, і синтаксис буде досить громіздким.

Хоча я теж починав з Haskell років 15 назад, занурення триває досі (= це цікава пригода і назад дороги не буде :D

Функціональне програмування — з чого почати

Не починати взагалі )

Повірьте власному і досвіду багатьох колег, які на тому чи іншому етапі загорілися функціональщиною, но через пів року — рік, закидали. Приходить відчуття що ти пісяєш проти вітру.

Починати тільки якщо пре від матана і вам хочеться розвиватися в академічному напрямку. В практичному — функціональщина майже немає застосування.

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

Скоріше за усе або лише хотіли війти, але не було часу, або не зуміли.

В практичному — функціональщина майже немає застосування.

Ну... Екосистема Haskell достньо велика й дозволяє вирішувати багато різних задач. Програмістів на Haskell у тисячу разів менше, ніж Python, але у cabal є майже усе, й досить високої якості.

Скоріше за усе або лише хотіли війти, але не було часу, або не зуміли.

Саме так, тратилося багато часу на розуміння і написання того, що в імперативщини робиться за хвилину, яке легше до того читається, рефакториться і супортиться.

Я допускаю що ті, які з самого початку починали з функціональщини, які 10 років в хаскелі, 15 років в емакс чи вім, вони набагато вільніше себе там почувають. Но якщо раз спробував імператившину, чи провів в ній все життя, фцнкціональні мови будуть для тебе кайданами, постійно будеш відчувати що пісяєш проти вітру.

Це як якесь моноколесо. Нафіга вчитися на ньому їздити якщо є електричний самокат че велік?

Функціональщина сама по собі не зло, залюбки використовую багато елементів функціональщини в своєму імперативному коді, но функціональні мови програмування які на 90% побудовані навколо функціональщини — зло.

Саме так, тратилося багато часу на розуміння і написання того, що в імперативщини робиться за хвилину, яке легше до того читається, рефакториться і супортиться.

Таке враження, що ви говорите більше про використання map, filter vs цикли. Але це дуже маленька частина функціональщини.

о якщо раз спробував імператившину, чи провів в ній все життя, фцнкціональні мови будуть для тебе кайданами, постійно будеш відчувати що пісяєш проти вітру.

Ну... Усе своє життя я програмував на імперативних мовах, починаючи з Turbo C 1.5 на початку 90-х, коли мені було 15. Haskell-ем я почав займатися коли мені було вже за 40. Дуже шкодую, що свого часу вивчав різні .NET, а не зайнявся Haskell раніше. Також таке відчуття, що усе життя я копіпастив монадичний код, думав що це неминуче зло... А з’ясувалося, що це я був обмежений.

залюбки використовую багато елементів функціональщини в своєму імперативному

Монади? Як, поділиться :-) ADT? пишете на Rust?

Це як якесь моноколесо. Нафіга вчитися на ньому їздити якщо є електричний самокат

Тому що з моноколесом руки вільні, воно більш стабільне за рахунок більшого діаметру, більш компактне)

Так, тільки на вєліку ти до точки доберешся в 5 раз швидше, буде час з вільними ногами і руками зайти в кав’ярню, випити каву, і почекати того, хто на моноколесі )

Да і більше речей на вєлік можна погрузити )

з кількістю речей — згоден. А ось зі швидкістю — ні. Бо деякі моноколеса і за 50 гоняють, я б подивився на середньостатистичного велосипедиста, який би рухався з такою швидкістю не з гори... Ну і з моноколесом якось простіше піднятися на n-й поверх лифтом. І не завжди можна вел залишити поруч з офісом...

Я думаю, що для деяких задач ФП буде оптимальніше.

Бо використовуючи в роботі Python я інколи з сумом пригадую, що щось подібне я значно простіше робив з Maple/Mathematica ;) (зазвичай це про перетворення різних структур даних)

Рекомендую книгу Дениса Шевченко — О Haskell по-человечески

Дуже спрощено як на мене, на кшталт грокаємо алгоритми. Настільки спрощено, що часом може виникнути хибне непорозуміння. Я подивився на монади та на do-нотацію. Приклади найпростішого використання без жодного пояснення, окрім: можна написати так і воно запрацює.

Спробуйте TypeScript та fp-ts

Ну... виглядає як спроба реалізувати фічі з Haskell на мові, яка на це не дуже спроектована. Без документації, прикладів та великого досвіду використання у лібах. От, дивимося:

Functor.ts.html

Інтерфейси:

Functor (interface)
Functor1 (interface)
Functor2 (interface)
Functor2C (interface)
Functor3 (interface)
Functor3C (interface)
Functor4 (interface)

Тобто я це можу зрозуміти, якщо ти програмуєш на Haskell, але життя заставило тебе програмувати на ts. Але як початок... розбиратися треба на порядок більше, як на мене.

Є гарні статті, та навіть книга автора. Якщо потрібно більш просте то є most adequate guide книжка на js, щоб зрозуміти що таке монада, функтор ті інші терміни. Все одно через якийсь час повернешься до імперативного програмування або ооп, з невеликими вкрапленнями функціональщини.

Ну з цієї точки зору можна і з Python нікуди не переходити
docs.python.org/...​.12/howto/functional.html

Да и с Rust...

Typescript та fp-ts не йде в порівняння з python ніяк. Я з ним працюю більше вже ніж 3 роки, тому можу щось розказати про нього.

Для вашого запиту просто щоб повчити щось функціональне та академічне то можно спробувати haskell.mooc.fi
Це курс хаскелю від університету Хельсінки, безкоштовний з задачами та теорією

Все одно через якийсь час повернешься до імперативного програмування

Це просто шлях через fp-ts виглядає для мене досить тупіковим. Зрозуміти, що таке монада? Але без do-нотації використання досить незручне. Знову ж таки, припустимо, що можна розібратися у концепції, якщо продертися крізь купу складнощей та деталів ліби. Для мене все це не очевидно, але припустимо. Що далі? Жодного практичного прикладу немає. Жодних ліб на базі ts-fp немає. Звісно, що тобі треба повертатися з вакууму в реальний світ.

Знову ж таки, бібліотека виглядає більше як проба піару TS: дивіться, можна написати майже як у Haskell. Але... у репо автор зробив 2200+ комітів, другий мейнтейнер ще 69 комітів. Тобто виникає враження, що окрім автора з цим ніхто не розібрався :-) І виникає питання: «Навіщо?» Ну хоча б монадічний парсер написали.

Якщо брати Real World Haskell, то там остання частина це суто практичний аспект, а саме як будувати сервіси, мережеві застосунки, парсери, GUI, таке інше. Тобто ти бачиш, як ці аспекти працюють та допомагають писати код. На Haskell є навіть проект операційної системи — дослідження, як чисті функціональні мови прилаштовані до таких задач. Тобто можна рухатися далі: писати щось корисне, або глибже закопувутися в теорію, скажімо type dependency programming lanugages.

Скільки ви продакшен коду зустріли на практиці на хаскелі? Питаю тому що fp-ts зустрічав та працював у Readdle, Grammarly та є знайомі з Klarna.
Також є нова бібліотека effect ts, я з нею не працював або схоже що вони зливаються з fp ts, на сайті є багато прикладів
effect.website

Скільки ви продакшен коду зустріли на практиці на хаскелі?

Трохи писав тулзи для себе, трохи дивився на OpenSource проекти. А от жодного рядку на TypeScript у продакшені особисто я не бачив.

Тут залежить від експертизи, як на мене, досвіду.

Ось класичний вже курс який не потребує ніяких попередніх знань ФП www.coursera.org/...​la-functional-programming
В курсі послідовно розглядаються основні концепеції сучасного ФП.

Якщо вам хочеться спочатку ознайомитися з термінологією, ну і взагалі зрозуміти що буває в ФП, то тут є десь 30 дуже якісних статей на досить різноманітні теми з ФП fprog.ru

Пролистал из любопытства. Какой-то хардкор. Но если можешь такое читать, то круто конечно. Вот тут самая известная жесть из мира ФП если такой формат не пугает maartenfokkinga.github.io/utwente/mmf91m.pdf (Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire).

Вот тут самая известная жесть из мира ФП

Ну... математичний опис лінивого лямбда-обчислення, в принципі там головна проблема це математична мова. Ну а так є lambda cube і там в кожній точці можна знайти формальний опис.

Викинь, а краще спали :) якщо починати знайомство з таких книжок, ними воно й закінчиться.

Згадав старий анекдот: «... а що, томатний є?» :D

що з нею не так? У мене зазвичай проблеми з часом на це, а ніяк не з книжками...

Бо вона по-перше дуже нецікава (може бути проблемою перекладу, я не дивився на першоджерело) а по друге «про все і ні про що», як на мене. Якщо більше цікавлять теоретичні аспекти, то читати треба інші книги (типу Types and Programming Languages Пірса). Якщо цікавлять питання практичного використання, то тим більше. Просто порівняй рандомний розділ присвячений ML цієї книги й рандомний розділ з Real World OСaml (чи з цього підручника), чи подивись Domain Design Made Functional. Я чесно не розумію навіщо піпл часто намагається робити з ФП якусь сакральну технологію для яйцеголових фріків замість того, щоб показувати що ФП елегантно і надійно вирішує цілком реальні практичні проблеми...

Ну ось саме заради таких коментарів, як ваш я і створив топік.

Бо ця книжка нагуглилася, а ті, що перелічили ви — ні.

Якщо більше цікавлять теоретичні аспекти, то читати треба інші книги (типу Types and Programming Languages Пірса).

Трохи застаріло, більш сучасна робота за участі того же автора це Software Foundations. Ну і там все виріфіковано CoQ, а це все близьмо до OCalm. Частина доказів портована на Agda, а це близько до Haskell.

Ну... там просто більше теоретичні аспекти.

Після закінчення курсу теоретичної фізики в університеті, я б не сказав, що мене може лякати математична теорія, навіть навпаки ;)

Теорфізика це більше диференційні рівняння. Там більше алгебра.

Якщо не лякає, то ще одно посилання:
Software Foundations

Серія «Основи програмного забезпечення» — це широкий вступ до математичних основ надійного (веріфікованного) програмного забезпечення.

Головна новизна серії полягає в тому, що кожна деталь стовідсотково формалізована та перевірена машиною: увесь текст кожного тому, включаючи вправи, є буквально «скриптом перевірки» для асистента перевірки Coq.

Мене більше лякає, що книжок на почитати у мене тепер на роки вперед ;)

Дякую!

Функціональне програмування — з чого почати

Почати треба з розуміння задачі. Якщо так як ви сформулювали:

Якщо у вас виникне питання «Щоб що?» — то just for fun! Ну і мізки розім’яти...

Тоді Хаскел, ну можна ще Скалу.

Якщо задача зрозуміти концепції, навчитись їх застосовувати, та покращити свій професійний рівень, то тут треба брати те, що ви будете реально використовувати. І тут конкретна мова йде під ваші задачі.
Тайпскріпт — непогана точка старту, має і типи, і ФП можливості. Для девопса може бути цікава точка прикладання — AWS CDK.
Якщо користуєтесь емаксом (або плануєте), то елісп. Роботу з типами ви навряд чи там відпрацюєте.

Якщо користуєтесь емаксом (або плануєте)

Якось emacs не пішов, а ось vim зачепив, не зміг вийти, скажемо так ;)

А би радив Haskell, моє порівняння приблизно таке:
Clouse/Lisp — це все ж динамічна типізація, тобто там немає типів. Тому це як би відповідь на питання, чи є компіляція — якщо типів немає, то придумати ефективну компіляцію складно. І знову ж таки, розвинута система типів (про що й писав статі Dmitry Astapov) це те, що хочеться вивчити.
F#/Scala — ну... по-перше, я не дуже знайомий зі світом JVM, та і .NET не дуже. По-друге в описах можна прочитати, що це мультипарадигменна мови з підтримкою ООП. Мультипарадигменна для мене це як жінка, яка дає багатьом чоловікам: не можна використати повністю переваги однієїпарадігми, до інші заважають. По-третє, виникає спокуса використовувати звичні парадігми, а потім казати, що я освоїв ФП :-)
Erlang/Elixir як на мене виглядають більше нішевими телеком-мовами (висока паралельність).

Тому лишається лише OCalm та Haskell. Про OCalm я більше знаю, що він часто використовується у зв’язку з CoQ. Цікава альтернатива, але все ж таки я голосую за Haskell, бо там монади інтегровані в мову, а це дуже цікавий та потужний аспект функціонального програмування.

Далі, ще є мови програмування з dependency type, на кшталт Idris, Agda, CoQ, Lean. Це наступний крок розвитку функціонального програмування, коли мова підтримує математичні твердження у повному обсязі, тобто ми можемо математично довести як будь яке твердження відносно коду, так і будь яке математичне твердження взагалі. Теж дуже цікаво, але трохи академічно.

Як почати? Ну... складно сказати, 10 років тому я би порадив Real World Haskell. Дуже гарна книга, де в деталях розібрано багато нюансів. Але.. Екосистема Haskell дуже швидко розвивається, тому друга частина книги сильно застаріла через використання старих версій пакетів: з коробки не запуститься.

В будь якому разі раджу ком’юніті в Discord: Join the Functional Programming Discord Server!
All about functional programming with Haskell, Lisp, ML and proof checkers like Idris, Lean, etc. | 14445 members

І знову ж таки, розвинута система типів (про що й писав статі Dmitry Astapov) це те, що хочеться вивчити.

Після багатьох років напівпрофесійного (бо мені платили не за це, тобто саме написання коду не було моєю основною задачею) програмування на Python — підхід до роботи з типами мені сподобався в Rust... Тобто, я хочу сказати, що розвинена система типів може бути і без ФП, мабуть.

Щодо JVM/.NET — У мене трошки інша претезія, скажемо так. Необхідність мати на платформі ту саму систему виконання. Це і до Python теж відноситься, так.

Не те, що це щось принципове та погане, але... (І цілком доречно, що навіть «бінарники» вимагають наявність C/C++ стандартної ліби в системі) ... але хочеться мати можливість створити бінарник, в якому є все, що треба — і тільки це. В якомусь ідеальному світі ;)

По-третє, виникає спокуса використовувати звичні парадігми, а потім казати, що я освоїв ФП :-)

З одного боку так, з іншого, суто практичного боку — класно мати можливість використовувати найефективніші підходи з обох підходів, в залежності від задачі. Хоча з точки зору вивчення — абсолютно згоден.

За посилання дякую.

підхід до роботи з типами мені сподобався в Rust... Тобто, я хочу сказати, що розвинена система типів може бути і без ФП, мабуть.

Ну... розвинена може бути більше/менше... ADT (алгебраїчні типи даних) у Rust були явно натхненні функціональними мовами програмування, такими як Haskell. Але у Haskell типи більше потужні. Ну а dependency types, як на мене, це вершина потужності, коли система типів рівносильна математиці, більшої потужності в житті немає.

З одного боку так, з іншого, суто практичного боку — класно мати можливість використовувати найефективніші підходи з обох підходів,

Проблема у тому, що вони вбивають одне одного. Парадигма це часто обмеження, яке дозволяє досягти певних цілей. Наприклад, структурне програмування це відмова від goto, що дозволяє створювати більш зрозумілий код. Або, якщо брати Rust, то ми обмежуємо себе тим, що в нас у рантайм або один унікальний вказівник, за яким ми можемо записувати, або багато вказівників, які дозволяють нам лише читання. Це дозволяє компілятору доводити відсутність певного сорту багів як дата рейси, тощо.

Якщо ми беремо заборону на змінні (чисте функціональне програмування), то ми отримуємо контрольованість side effects та можливість автоматичного багатопоточного виконання коду компілятором.

Тому... все ж таки я більше схиляюсь до того, що окремий компонент треба розробляти с використанням тієї парадигми, що краще відповідає.

Знову ж таке, якщо брати навчання, то краще повністю зануритися.

Тому... все ж таки я більше схиляюсь до того, що окремий компонент треба розробляти с використанням тієї парадигми, що краще відповідає.

Я мав на увазі, що в залежності від задачі можна писати в різних парадигмах, але однією і тією-ж мовою. Звісно. що це вимагає певної дисциплини, і це, скоріше за все, не про навчання.

Я мав на увазі, що в залежності від задачі можна писати в різних парадигмах, але однією і тією-ж мовою.

Оце як раз добре не працює, як на мене. Якщо концепція це обмеження, то коли ми додаємо іншу концепцію, то ми нівелюємо обмеження, в результаті чого компілятор не може нам повноціно допомогти. Наприклад в Rust, є концепція safe code. І нам треба завжди це чітко розділяти.

Чи одна мова краще я не розумію.

коли ми додаємо іншу концепцію, то ми нівелюємо обмеження, в результаті чого компілятор не може нам повноціно допомогти.

З цієї точки зору я не подумав, згоден.

Не те, що це щось принципове та погане, але... (І цілком доречно, що навіть «бінарники» вимагають наявність C/C++ стандартної ліби в системі) ... але хочеться мати можливість створити бінарник, в якому є все, що треба — і тільки це. В якомусь ідеальному світі ;)

Ну...

$ cat hw.hs
module Main where

main :: IO ()
main = putStrLn "Hello World!"

$ ghc hw.hs                              
[1 of 2] Compiling Main             ( hw.hs, hw.o )
[2 of 2] Linking hw 

$ ldd hw
    linux-vdso.so.1 (0x00007ffd610e9000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc227a3e000)
    libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fc2279ba000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc2277c8000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc2277be000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc2277b8000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc227795000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fc227bab000)

$ ./hw
Hello World!

тобто є все, що тобі треба. Навіть, якщо брати Agda, то оскільки вона використовує Haskell під капотом, то... не знайти відмін:

$ cat hw2.agda
module hw2 where

open import Agda.Builtin.IO
open import Agda.Builtin.Unit
open import Agda.Builtin.String

postulate
  putStrLn : String → IO ⊤

{-# FOREIGN GHC import qualified Data.Text.IO as Text #-}
{-# COMPILE GHC putStrLn = Text.putStrLn #-}

main : IO ⊤
main = putStrLn "Hello world!"

$ agda --compile hw2.agda
Checking hw2 (/home/avs/projects/poiuyt/hw2.agda).
Compiling hw2 in /home/avs/projects/poiuyt/hw2.agdai to /home/avs/projects/poiuyt/MAlonzo/Code/Qhw2.hs
Calling: ghc -O -o /home/avs/projects/poiuyt/hw2 -Werror -i/home/avs/projects/poiuyt -main-is MAlonzo.Code.Qhw2 /home/avs/projects/poiuyt/MAlonzo/Code/Qhw2.hs --make -fwarn-incomplete-patterns
[6 of 6] Linking /home/avs/projects/poiuyt/hw2

$ ldd ./hw2
	linux-vdso.so.1 (0x00007fffbddb5000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff192b74000)
	libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007ff192af0000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff1928fe000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff1928f4000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff1928ee000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff1928cb000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ff192ce1000)

$ ./hw2 
Hello world!
хочеться мати можливість створити бінарник, в якому є все, що треба

Publishing your app as self-contained produces a platform-specific executable. The output publishing folder contains all components of the app, including the .NET libraries and target runtime. The app is isolated from other .NET apps and doesn’t use a locally installed shared runtime. The user of your app isn’t required to download and install .NET.

так, але там зазвичай не тільки те, що треба, а набагато більше, ніж треба. Умовний hello world буде на десятки мегабайт.

Звісно, пам’ять дешева, але такий підхід мені дуже не подобається. І з точки зору безпеки — теж.

У разі Haskell:

$ strip ./hw
$ ls -lh ./hw
-rwxrwxr-x 1 avs avs 1.1M Jan  3 20:04 ./hw

Забагато, але не десятки.

Менше, ніж Rust ;)

$ ./target/release/tmp 
Hello, world!

$ ls -lha ./target/release/tmp
-rwxr-xr-x 2 eking eking 4,3M січ  3 21:13 ./target/release/tmp

Ага, так значно менше:

$ ls -lha ./target/release/tmp
-rwxr-xr-x 2 eking eking 355K січ  3 22:23 ./target/release/tmp

На мак трошки більше:

$ cat hw.hs 
module Main where

main :: IO ()
main = putStrLn "Hello World!"

$ ls -lha hw
-rwxr-xr-x  1 eking  staff    12M  4 січ 13:21 hw

$ strip hw
$ ls -lha hw
-rwxr-xr-x  1 eking  staff   8,0M  4 січ 13:25 hw
hello world буде на десятки мегабайт.

Яке це має значення, якщо постановка задачі звучить «розім’яти мізки» ?

Ну я ж не просто так писав, що і практичність теж важлива ;)

Чисто розім’яти мізки — можна поставити Wolfram Mathematica — там взагалі майже все, що завгодно є ;)

Ну... dotnet треба ставити все одно під Linux. Знову ж таки, це ви F# рекламуєте так?

Ну автору OCaml подобається, а F# це і є Окамл під дотнет.

Де я казав, що мені OCaml подобається? Мабуть ви мене з Dmitry Astapov плутаєте ;)

Можливо, але все одно це класика )

За dotnet не підкажу, а коли дивився java десь у 2000, там можна було зібрати 1 exe файл, в який була інтегрована jre і нічого на цільовій машині мати не треба було — просто перенести цей файл.

Ніби то python так само пакується, але я не робив. Мабуть і dotnet можна (принаймні, не бачу технічних обмежень щодо цього, Але ж воно доволі велике буде...

Підписатись на коментарі