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

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

Після останніх статтей 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», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному3
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, то всі потрібні бібліотеки в вас скоріш за все будуть
тому що Clojure хоститься на JVM. Також, якщо вам треба буде знайти
утечку памʼяті то можна використати Yorkit profiler.

Буде складно використовувати REPL driven розробку спочатку,
але ви скоро зрозумієте що це зручно.

З досвіду Clojure проста мова, точно простіше 90% мов
програмування які існують, мабуть, навіть простіше 97%
мов які існують.

Якщо ви розберетесь з core, то зможете
писати все що вам подобається дуже швидко.

Дуже рада що вам це цікаво.

Після останніх статтей Dmitry Astapov у мене з’явилося трохи більше мотивації взятися за ще одну мову,

Там було не зовсім про функціональне програмування, а про розвинуті системи типів (які зазвичай є у функціональних мовах).
Тобто Erlang/Elixir/Clojure/Lisp можна викреслити (не маю нічого проти, але «make illegal state unrepresentable» — це не про них).
Вибір між Scala, F#, Haskell, OCaml буде доволі суб’єктивний, бо кожна має вагомі переваги та недоліки.

Суб’єктивно, я б порадив F# :), бо він:
— є в .NET SDK, не треба нічого встановлювати окремо
— одна з дуже небагатьох мов, яка компілює під усі наявні платформи (Linux/Windows/MacOS/Android/iOS/JavaScript/Wasm/PS4/PS5/Xbox/Switch/)
— доволі практичний, можна використовувати для скриптів
— є fsharpforfunandprofit.com — певно, це найкращий ресурс для новачків у FP.

— є в .NET SDK, не треба нічого встановлювати окремо

Ну це якщо у вас Windows — на Linux/Mac треба встановити ту саму .NET SDK ;)

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

Звучить доволі логічно в контексті FP)

Не погано в порівнянні з чим і для чого?
Але то не головне — знайти необхідність в натягуванні дотнет (сови) на лінукс (глобус) — то треба явно щоб щось пішло не так)

Складне питання, насправді.

В цілому, я не дуже люблю рішення від M$. З іншого боку, рочків так 15 назад я бажав мати плеєр, який буде менеджети всю мою колекцію музики, а її в мене було під 200Гб в mp3 — на той час доволі багато. Ну і бажалось, щоб пошук, щоб тегі з файлів, щоб обкладинки альбомів автоматично...

Тому перебирав я їх доволі багато з тих, що були доступні в Debian на той час. І зазвичай час на повне сканування всієї колекції був в кілька годин. Та й пошук не те, щоб зовсім інтерактивний. Навіть для плеєрів, що були написані на C++. Так ось найшвидшим за часом сканування і найінтерактивнішим пошуком (коли набираєш і воно по мірі набору фільтрує/шукає трекі колекції) був плеєр на ... Mono. Що дуже мене здивувало.

То вже застаріло — підхід який зараз проштовхують з (ще більшим ніж свій окремий тулчейн всім) bloatware вебпрограмуванням — ставити electron app замість звичайних прог (тобто девіз — дайош кожній прозі свій окремий браузер в окремому контейнері))

p.s. чогось spotify згадався

Все відносно, десятки нових гіг під нові електрони не всі хочуть докупляти. Але ми їх переконаємо що то для їх блага), чи принаймні що то дешевше вийде в сумі бо вебпрограмінг .

Доречі якщо аі в майбутньому проштовхнуть достатньо, то reasoning excuse дешевого та швидкого програмування — може і випаровуватися кудись.

Мені то дешеве та швидке програмування постійно муляє. Бо воно ще й небезпечне.

Колись у підлітковому віці у мене був ZX-Spectrum з 32кБ оперативки — і там була програмуліна, що будувала 3-вимірні графіки функцій (можна було задати) які можна було наближати, масштабувати та крутити просто клавішамі, інтерактивно. І це в 32кБ. І на тому проці...

32кБ оперативки — і там була програмуліна, що будувала 3-вимірні графіки

ого, круто хтось постарався, інші максимум що на сінклерах робили то трохи побейсекити (бо нічого зручнішого «чим» не було) чи в тетріс з бомберами пограти

demoscene,
ось де розкривається талант программіста, художника, музиканта,
при мінімумі можливостях домашніх по 80х показати максимум на що вони здатні,
ось наприклад, тема невичерпана й досі а навіть навпаки, зараз нова хвиля зацікавленовсті на ретро,
archive.assembly.org/...​ne-coding-zx-spectrum-101

У мене інколи викликають ностальгію старі термінали, але повернутися до них я б ніколи не хотів. Хоча стилізація нових під них виглядає прикольно, якщо не додає незручності. Наприклад клавіатури я обожнюю надтонки до яких можна ледве торкатися, і тихі, щоб вночі, працюючи, чути як в коридорі тікає годинник ;)

Але мене, як інженера, завжди надихають красиві і оптимальні рішення, коли можливості системи використані на 100%

а по терміналам випадково — plan9/cat9 підхід не пробували в *nix прикручувати? щось на зразок такої термінальної роботи (це демка з їх доки)
user-images.githubusercontent.com/...​fcf-bff0-fe5c3dd0a369.mp4

Ні, хоча деякий час працював з WindowMaker — Доволі прикольно було...

там не тільки відносно wm, сама ідея що термінал не обмежується шеллом з readline input і той input/output розглядався з любої позиції у текстовому вікні — була сподобалась, але теж до повної юзабельності у мене не дійшло

на Linux/Mac треба встановити ту саму .NET SDK ;)

так, треба встановити dotnet sdk, але F# встановлювати не треба
До речі,
— для java/scala, встановити jdk — недостатньо — треба ще maven/gradle/sbt
— для ocaml треба opam, і далі ocaml та dune
— для haskell — треба ghc і окремо stack/cabal

Зрозуміло, що для написання та відладки треба для будь-якої мови встановлювати багато чого.

Питання в тому, щоб не треба було встановлювати нічого, крім компільованої апки.

— для ocaml треба opam, і далі ocaml та dune
— для haskell — треба ghc і окремо stack/cabal

В Linux це одна команда, для Haskell це

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

Для OCalm це

curl -fsSL https://raw.githubusercontent.com/ocaml/opam/master/shell/install.sh | sh

Після цього вони створять окрему директорію, куди буде встановлено софт, та яку в будь який момент можна видалити. Треба лише прописати PATH. Усе інше можна встановлювати через ghcup та opam (різні версії компілятора, встановлювати яка має бути активною, ...)

У linux, зазвичай, використувують менеджери пакетів, а не запускають рандомні скрипти з інтернету без ревью.

Менеджери пакетів не раджу, бо це привʼязка до конкретних версій, часто застарілих. Це проблеми використання декількох версій, коли у тебе декілька проектів, та кожен вимагає свою версію.

Знову, я от бачу https://get-ghcup.haskell.org. Який це рандом? Якщо ворог сидить у домені haskell.org, то у нього вже багато місць від компілятора до утіліт куди додати злонавмисний код.

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

І все-ж таки пакети краще. І нормальний менеджер пакетів як встановлює так видаляє все коректно. Зі скриптами все не так гарно в більшості випадків.

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

так, всілякі докери рятують, але це рішення того-ж рівня, як і electron...

Зі скриптами все не так гарно в більшості випадків.

У разі Haskell це окрема папка, яку можна просто видалити за бажанням :-) Оскільки я знаю, у разі opam те ж саме.

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

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

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

Знову ж таки, поставив під окремим користувачем, воно тобі зовсім не заважає.

У разі Haskell це окрема папка, яку можна просто видалити за бажанням :-) Оскільки я знаю, у разі opam те ж саме.
Знову ж таки, поставив під окремим користувачем, воно тобі зовсім не заважає.

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

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

В реальному світі це буде docker контейнер, в якому буде проводитися білд, щоб забезпечити стабільність середовища. І більш-менш серйозний проект везе купу специфічних залежностей, тому додатковий рядок не змінить складність. Ну яка різниця, чи ти поставиш ghcup через менеджер пакетів, чи через командний рядок, коли потім через нього будеш ставити Haskell, cabal, потрібні пакети, тощо.

Ну а клієнт отримає на виході rpm або deb файл з бінарями. Або docker з бінарями. Або образ vShpere готовий до деплою.

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

Взагалі мені незрозуміло, навіть dev environment на кожному сервері, коли можна просто задеплоїти бінарі.

Ну а клієнт отримає на виході rpm або deb файл з бінарями. Або docker з бінарями. Або образ vShpere готовий до деплою.

Я стискався з системами, куди для сумісництва з в контейнер пихали все, що може знадобитися, і контейнер був під 10Гб.

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

Оптимізований контейнер був біля Гб, це в 10 разів швидше. Я вже не кажу про те, що місця на диску під все це треба більше, і все це гроші.

коли можна просто задеплоїти бінарі.

— ну, по-перше, бінарі теж мають залежності. а по друге, якщо пишуть софт на Python/Node/etc то там може бути той ще зоопарк окрім бінарів...

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

А чим твій підхід краще? Щоб воно скомпілювалося — теж треба час. Щоб налаштувати середовище для компіляції — теж треба час.

а по друге, якщо пишуть софт на Python/Node/etc

Ми ж розмовляємо про Haskell, який генерує саме бінарі. Ідея робити з кожного сервера девелоперську машину мені подобається менше.

А те що Python/Node може бути по іншому це так. Але компільовані мови це трохи інші проблеми. Тому «це не гарне рішення, бо вона погано працює з Python»... ну таке, якщо ти не працюєш з Python.

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

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

Лінковка системи як цілого значно зменшує розмір бінарів і час на їх скачування та встановлення. Мій десктоп з купою софту не первищує 20Гб під це. Якщо перетягнути все в контейнери — у мене може і Тб диску не вистачить ;)

Але-ж «пам’ять дешева», а «трафік жеж безлімітний» ;)

Коли є один бінарь — це ще не така проблема, коли в тебе купа «імеджів» на кілька Гб кожен — то час на оновлення та перезапуски системи росте, навантаження на мережу — теж. Це гроші. Звісно, що харним провайдерам тільки краще, що клієнт заплатить більше за більші стораджі, за більший трафік «але ж все просто і автоматично»

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

ghcup це також система управління пакетами, яка усе це теж вміє. Знову ж таки у Python ти використовуєш pip або conda, ти ж не ставиш усі пакети через менеджер пакетів OS, хоча міг би.

Час на компіляцію так, треба. але зібрати все в один образ — це теж не миттєва операція, якщо що

Але зібрати усе в один образ робиться один раз. Після цього білд тестується QA, запускаються тести, збираються метріки, ... І тільки після цього білдом може користвуватися замовник. А у тебе якось виглядає, що розробник зайшов на машину замовника, щось підправив, скомпілював, запустив. Ти пропагандуєш таку систему розробки?

Коли є один бінарь — це ще не така проблема, коли в тебе купа «імеджів» на кілька Гб кожен — то час на оновлення та перезапуски системи росте, навантаження на мережу — теж.

Ну роби rpm чи deb, мені в принципі не дуже зрозуміло, що ти пропонуєш. Обмежитися лише менеджером пакетів окремої OS? А потім прийде замовник з іншим дистрибутивом?

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

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

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

xkcd.com/927 ;)

Ще раз, ghcup це готовий менеджер пакетів для Haskell розробки. Більшість пакетних менеджерів встановлюються через

curl url | sh

наприклад, той же nixos. Тому який це велосипед? Я просто не розумію, до чого ці коменти.

Де ви бачили систему, де весь софт на одній тільки мові?

В реальному світі ви будете встановлювати частину софта через ghcup, частину через pip, частину через ще щось. І буде повнісінький бардак, коли щоб закрити дирку в ssl вам треба поновлювати всі набори пакетів одночасно, замість заміни однієї залежності для всіх.

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

nixos

Що там все так сумно що своїми скриптами все робити треба? В guix для того guix/guile (scheme impl.)

Обмежитися лише менеджером пакетів окремої OS? А потім прийде замовник з іншим дистрибутивом?

deb чи rpm маніфести покривають групу ос не один дистро, потім якщо треба більш широка дистрибуція для ендюзера — то покривається пакаджінгом в snap/flatpak, для того ні скрипти на колінках ні докери не потрібні

deb чи rpm маніфести покривають групу ос не один дистро,

Тобто ти хочеш сказати, що якщо rpm працює на Amazon Linux 2, то він запрацює на Cent OS? snap теж не впевнений, знову ж таки, поставити snap щоб поставити через нього ghcup лише для того, щоб не скачувати його скриптом?

Що з amazon linux2 — ноу айдіа, якщо про конкретику — то нп на obs з маніфестом який підтягує відповідні deb/rpm «маніфести» з тарболом разом — збираються (автоматично) пакети під всі найбільш розповсюджені ос в яких rpm чи deb, включно і з градацією по версіям окремих дистро. Це як приклад.
Flatpak/snap гарантує потрібний для когось більш універсальний підхід в плані cross portability між дистрибутивами — тобто відповідний гарантований environment/runtime (+свій рівень сек’юріті).

Що там хто скачує скриптом щоб запропонувати кастомеру потім докер і гамак для секса — не дуже цікаво.

все-ж таки пакети краще

То без питань (для тих хто в *ніксах робить) що пакети по менеджменту на порядок краще ніж ручні сетапи в local чи home.

Цікаве інше питання скоро буде — відносно як то краще пакувати. Якщо дивитись на тенденції уходу все більш в пакетизацію умовну контейнерізацію з snap/flatpak сторами замість звичайної пакетизації плюс репо, і також перехід всього системного в immutable стан (з immutable oses).

Я вважаю, що immutable не взетить. Воно працює виключно у обмежених випадках, великий owerhead по пам’яті.

Та й великого сенсу від нього немає — оця ідея «давайте зберігати попередні контейнери, щоб завжди була можливість повернутися до попереднього стану» тупо не враховує, що повернути міграції БД майже завжди неможливо, або з втратою даних. Це тупо протиричіть ідеї SQL про те, що якщо транзакція пройшла — вона невідворотня. Та й сторонні API ти не відкотиш до поереднього стану.

Тож це працює на одну-дві версії назад, а далі — то фігня. Немає машини часу.

Всі ідеї контейнеризації з точки зору безпеки — так, є сенс. Але теж не треба чекати золотої кулі.

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

контейнери

Трохи інше малось на увазі: розбивка по софту та підхід до пакаджінгу з immutable OSes. На прикладі GnomeOS якто бачать: — системний софт повністю immutable під час роботи, а весь юзер софт тільки в flatpak. Системний софт (всі сервіси, проги, все що хоч трохи критичне для роботи) можна міняти тільки атомарно як цілий образ за допомогою systemd-sysupdated (без можливості — а поміняю я окремо щось в системному софті). Все що некритично для роботи системи відправили на розсуд юзера чи ставити то з flatpak store.
Розділ софта system/user чимось нагадує bsd, тільки з більш сучасним і reasonable підходом.

контейнери... для економії часу і вирішення проблеми з залежностями

Так це snap/flatpak — гарантовані енвайрмент і рантайм (ліби, версії, і т.п.), плюс сек’юрність у вигляді що можна через окремі неймспейси, куди доступ є по підсистемам, і т.п. Overhead у порівнянні з стд пакаджами є трохи (тому і не полюбляють певно), хоча той оверхед і невеликий якщо порівнювати з докер рішеннями.

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

Тобто страждає гнучкість, час виходу оновлень, термін підтримки та кількість конфігурацій.

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

це як на смартфонах

Так, то нагадує ChromeOS на компах з їх app store

перезбирати на кожну заплатку безпеки всю систему — таке

— якщо то в базовій системі — припливає якийсь бінарний diff для нового образу, ресурси провайдера/дистриб’ютора ос зазвичай достатні для перезібрати новий імідж.
— якщо то софт з snap/flatpak — там відповідно свої окремі частини (Гарантовані рантайми трохи завеликі, але не так щоб занадто. А який там софт дистрибутять — то який є, кожний зі своїм підходом).

Ззовні виглядає краще і з меншими оверхедами ніж рішення з докер хаосом.

— якщо то в базовій системі — припливає якийсь бінарний diff для нового образу, ресурси провайдера/дистриб’ютора ос зазвичай достатні для перезібрати новий імідж.

ну по факту, оновлення на смартфони чи яблучні девайси чи ChromeOS достатньо великі. І не такі вже часті, порівняно з, наприклад, оновленнями пакетів в дістрах.

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

Я банально порівнюю свій мак, та лінуксовий десктоп — поновленя пакетів прилітають раз в пару днів, оновлення макось раз на пару місяців. Кількість підтримуваних конфігурацій для Linux складно й оцінити, кількість підтримуваних конфігурацій мака — ;)

Подавляюча більшість дистрів чудово живе без перевстановлення 5-10 рочків, на середній смартфон оновлення прилітають перші рік-два.

Тож реальність дуже далека від ідеалу.

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

При розбивці на sys/user soft — пакети які системні (в системному образі) оновлюються не часто, тай то ненормально якби вони апдейтилися кожного дня. Пакети які в snapflatpak — хоч н-разів у день, вони не пов’язані з системою.

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

Та від докера і я не в захваті...

Python — найкращій вибір для мене

І для мене. :)

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

Починати краще з 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 через Xmonad wm?

З одного боку: чому ні. Користуватись результатом власної праці приємно. З іншого, мабуть це буде переважно знайомство з синтаксисом: мені важко уявити якусь складну абстракцію щоб воно потребувалось у процесі написання конфігу. Та і якщо користуватись, то постійно «ламати» віконний менеджер під час розробки — не дуже зручно. Плюс зараз здебільшого переходять з іксів на Wayland, тож може є сенс контріб’ютити в waymonad натомість (втім воно дуже сире, і виглядає закинутим). Хоча якщо є бажання погратись з мовою, play.haskell.org плейграунд буде зручнішим на самому старті. Можливо також є сенс приділити увагу вивченню дещо простішого для розуміння OCaml, щоб знизити собі поріг входу до просунутих можливостей виразності мови, як то GADT, type families та й type classes краще зрозуміти теж.

Дякую!

з іксів на Wayland, тож може є сенс контріб’ютити в waymonad

Нубське питання що дасть тут Wayland + waymonad при вивченні функціонального програмування?

Можливо також є сенс приділити увагу вивченню дещо простішого для розуміння OCaml, щоб знизити собі поріг входу

OCaml відкритий ЯП типу Python чи ні? Як справи з OCaml на Лінукс?

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

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

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

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

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

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

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

Ну... Екосистема 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-нотацію. Приклади найпростішого використання без жодного пояснення, окрім: можна написати так і воно запрацює.

Ну... виглядає як спроба реалізувати фічі з 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 зачепив, не зміг вийти, скажемо так ;)

Чому саме так у Вас вийшло з vim та emacs?

Складне питання. Частково — так історично склалося, частково — нічого зручніше не знайшов. Зараз для коду використовую ще Zed (і там є режим vim). Взагалі не люблю, коли інтерфейс перевантажений і панелей та підказок забагато. Наприклад Visual Studio та VSCode мене бісять. (доводилось допомагати донці у навчанні, а VSCode ще й співробітники використовують. Завжди дивує, коли вони роблять кліків мишкою більше, ніж я натискань на клавиши — навіщо робити собі життя складніше?)

Коли я вперше сів за консоль десь наприкінці 90-х, я пробував все, що там було доступно. І спочатку мені а ні Vim, а ні Emacs не здалися зручними. У FreeBSD я користувався ed (якщо не помиляюся) — бо він доступний завжди тупо з початку встановлення системи. А у нас в університеті були слабеньки машинки, ще 386 та 486 тупо як роутер, маленький файловий сервер та пошта (для тих, хто вмів ;) ) - там GUI не було. На Linux системах це були nano та mcedit.

Але пізніше і почав працювати в місцевому провайдері і там були Solaris-сервери, де був доступний виключно vim. Так як самі по собі сервери були ліцензійні, з вже встановленим софтом, які навіть оновляти самостійно неможна було, не те, що щось встановити — тільки правити конфіги (це була система перекодування відеопотоків з супутника для трансляції в мережу), то варіантів, крім як розібратися з Vim не було. Щоб пришвидшити навчання я став працювати з ним і на робочій машинці, та й на серверах. І виявилося, що заміна регулярними виразами — це неймовірно зручно. ;) Принаймі, зручніше, ніж працювати в інших редакторах. Особливо, коли в тебе купа доволі великих конфігів, і пропустити щось — вкрай не бажано. Бо покласти якийсь сервер — це отримати купу дзвінків у підтримку, а хлопці та дівчата сидять у сусідній кімнаті і можуть жеж зайти не чаю з кавою випити, а запитати, що за :D :D :D :D

З того часу і користуюсь.

додам що — після того як з’явилась підтримка lsp у vim/nvim то програмувати з ними стало значно зручніше, без них вже важче кодити коли вже звик до того

Завжди дивує, коли вони роблять кліків мишкою більше, ніж я натискань на клавиши — навіщо робити собі життя складніше?)
Коли я вперше сів за консоль десь наприкінці 90-х, я пробував все, що там було доступно. І спочатку мені а ні Vim, а ні Emacs не здалися зручними. У FreeBSD я користувався ed (якщо не помиляюся) — бо він доступний завжди тупо з початку встановлення системи. А у нас в університеті були слабеньки машинки, ще 386 та 486 тупо як роутер, маленький файловий сервер та пошта (для тих, хто вмів ;) ) - там GUI не було. На Linux системах це були nano та mcedit.
Але пізніше і почав працювати в місцевому провайдері і там були Solaris-сервери, де був доступний виключно vim.

Оо! Дуже дякую за таку розгорнуту відповідь!)
Тобто я бачу vim це справа звички у Вас? Бо не було GUI і працювали в консолі.
У мене навпаки, звичка до миші з win95)
Як я не намагався постигнути силу клави не виходило навіть у Лінукс обираю GUI DE типу xfce замість tiling wm:)
Можливо знову ж, звичність до клави та текстонлі софта через професійну діяльність коли постійно маєш справу з текстом, то все одно прийдеш до vim/emacs/tiling wm?

Тобто я бачу vim це справа звички у Вас? Бо не було GUI і працювали в консолі.

Насправді — ні. Бо з PC я почав працювати якраз з вінди — з 3.11 на 386/486 ;) І на нашій кафедрі була всюди вінда.

З Word я почав працювати раніше, ніж з LaTeX — але спробувавши раз, повертатись на Word, це як після F-35 повератись на АН-2. Ну з точки А то точки Б долетіти можна, але...

Але це не означає, що я принципово не люблю GUI. У мене Gnome на Linux десктопі та Mac. Просто є деякі речі, які в консолі робити швидше та оптимальніше. Наприклад, мені не так давно було треба знайти всі ресурси у terraform провайдері, які мають налаштування http протоколу — зробив локально клон репозитория з кодом, за допомогою grep/awk я швидко це зробив, та ще й результат відразу у вигляді тексту, що я просто вставив в таску.

Так само я міг раніше парсити логі веб-сервера і отримувати результат у вигляді, який можна напряму вставити в консоль Cisco/Juniper щоб заблокувати, наприклад. Не в консолі це значно складніше і довше.

Миша в консолі чудово працює також. Доречі, мене завжди дратувала відсутність у вінді можливості виділити слово або строку подвійним або потрійним кликом і вставити під курсор середньою кнопкою миші — це швидше, ніж ctrl+c/v або по меню правою кнопкою. Я не відмовлявся від миші ніколи.

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

Дякую!
Можна оффтоп?
Як Ви виросли до ДевОпса і які для цього треба мати мастхев скіли як хард так і софт?

Не можу сказати, що мав це за ціль. Якось склалося. Через SysAdminа, який любить програмувати та автоматизувати ;) Це якщо коротко.

І я не можу сказати, чого на цьому шляху було більше — скілів чи випадковості ;)

Щодо софт скілів — то нічого принципово особливого. як у будь-якого інженера — вміти зрозуміти замовника, вміти донести свою точку зору (технічні обмеження чи особливости рішення). Вміння домовитись.

Щодо хард — мені завжди було цікаво як все працює. І це не тільки про ІТ. Все життя з задоволенням читаю (і намагаюсь розібратися) науково-популярну літературу. За освітою я взагалі — фізик. Якщо з чимось працюю — намагаюсь дійти до повного розуміння роботи системи. Звісно, що можу на початку взяти готове рішення, коли треба швидко. Але намагаюсь розібратися як це працює. І це відноситься як до технічних систем, так і до суміжних областей — наприклад, працюючи з замовником (чи як частина команди великого бізнесу, як зараз), намагаюся зрозуміти як працює цей бізнес, щоб краще розуміти як вимоги до системи, так і до організації моєї роботи (не знаю, чи це хард, чи це софт скіл)

Конкретні технології не бачу великого сенсу перераховувати — у кожного свій шлях. Але базові — робота мережі (на всіх рівнях — тут мене рятує кілька років досвіду роботи у провайдері). Програмування — тут не стільки алгоритми та мови, скільки загальна архітектура, підхід до створеня продукту (це важливо для організації деплою, наприклад, бо бо треба ж розуміти, чому саме так, і як саме роблять це розробники), вміння відладки коду. Тут рятують пет-проекти як для себе, так і не зовсім пет, але автоматизація роботи за власною ініціативою, як то написання програмних рішень з нуля — коли скриптів недостатньо (це більше про великий бізнес)

Дякую. Звучить круто якщо так вийшло «само») Але складно мабуть усе це тримати в голові під контролем? Взагалі зазвичай ДевОпс це робота в офісі на місці чи віддалено? Просто знаю що звичайний сисадмін це біганина та цілковитий тиск з боку інших робітників, якщо немає помічників.

В голові тримати не складно ;)
Можна в офісі, можна віддалено. Я працюю віддалено.

звичайний сисадмін це біганина

то дуже і дуже неправильний сисадмін, якщо бігає — щось явно пішло не так

А би радив 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 — там взагалі майже все, що завгодно є ;)

Якщо не використовувати reflection, то не буде

$ cat hello.fsx
#!/usr/bin/env -S dotnet fsi
System.Console.WriteLine("Hallo there, from F#")

$ fflat hello.fsx --small
$ ls -has hello
984K hello*
$ ./hello
Hallo there, from F#
$ ldd hello
	linux-vdso.so.1 (0x0000716aa5021000)
	libdl.so.2 => /usr/lib/libdl.so.2 (0x0000716aa4fe9000)
	libc.so.6 => /usr/lib/libc.so.6 (0x0000716aa4df7000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x0000716aa5023000)
	libpthread.so.0 => /usr/lib/libpthread.so.0 (0x0000716aa4df2000)
fflat F# native script compiler

Зі scala native воно так само буде

$ sbt new scala-native/scala-native.g8
name [Scala Native Seed Project]: hallo-there
$ cd hallo-there
$ sbt run
$ ls -has target/scala-3.3.3/hallo-there 
1,3M target/scala-3.3.3/hallo-there*
$ strip -s target/scala-3.3.3/hallo-there
$ ls -has target/scala-3.3.3/hallo-there 
956K target/scala-3.3.3/hallo-there*
$ target/scala-3.3.3/hallo-there
Hello, world!
$ ldd target/scala-3.3.3/hallo-there
	linux-vdso.so.1 (0x00007ea5d8693000)
	libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007ea5d8200000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007ea5d8108000)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007ea5d8543000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007ea5d7f16000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ea5d8695000)
Але для чогось менш тривіального у вас будуть «десятки мегабайт.» з будь-якою мовою.

ну... Rust, наприклад, достатньо компактний:

$ du -hs *
6,1M	file-sync-rust
2,5M	pam_tbot_send
3,1M	tfvarsauto

Звісно, що то не дуже великі програмки, але й не Hello world

Наскільки я розумію — недолік раст не тільки у файлрозмір з тулчейн який йде разом з софтіною, а те що нп у випадку з С якась системна .so шариться всіма (тобто в сумі системних ресурсів заюзано небагато на всіх разом),
тоді як з раст прогами — там у кожної свій (щей часто з іншого lastnight build тулчейн) код який не шариться між ними. Тобто одна така прога то окей, а багато раста в системі — то наступний oops знову буде.

так ніби то ні:

$ ldd /usr/local/bin/pam_tbot_send 
	linux-vdso.so.1 (0x0000ffffaf4b1000)
	libssl.so.3 => /lib/aarch64-linux-gnu/libssl.so.3 (0x0000ffffaf160000)
	libcrypto.so.3 => /lib/aarch64-linux-gnu/libcrypto.so.3 (0x0000ffffaed00000)
	libz.so.1 => /lib/aarch64-linux-gnu/libz.so.1 (0x0000ffffaecc0000)
	libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffffaec80000)
	libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffffaead0000)
	/lib/ld-linux-aarch64.so.1 (0x0000ffffaf474000)
Тобто не схоже, щоб додаткові ліби тягнув. А якщо подивитись на розміри його тулчейну:
$ du -h /usr/local/bin/pam_tbot_send 
2.3M	/usr/local/bin/pam_tbot_send


$ du -hs .rustup/toolchains/stable-aarch64-unknown-linux-gnu/*
86M	.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin
20K	.rustup/toolchains/stable-aarch64-unknown-linux-gnu/etc
702M	.rustup/toolchains/stable-aarch64-unknown-linux-gnu/lib
1.7M	.rustup/toolchains/stable-aarch64-unknown-linux-gnu/libexec
709M	.rustup/toolchains/stable-aarch64-unknown-linux-gnu/share
Воно явно його не тягне в середину. Можна ще повикидати всіляки обробники panic але то вже таке.

Все не тягне з тулчейн, то булоб занадто в квадраті. Можна простіше спробувати — зібрати три різні helloworld проги різними раст версіями компайлера і подивитися що вони розшарять між собою з тих додаткових кіл/мег що додали в код. Потім порівняти те саме з сі.

C не тягне з собою обробку panic — коректного очищення ресурсів, звідси його теж можна викинути. Але 2.5Мб вже не так й багато.

Принаймні, це не десяткі Мб. І ресурси (сокети, файли, памʼять) все-ж краще підчіщати.

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

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

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

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

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

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

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