image


Несколько лет назад были очень популярны статьи о том, „как ввести типы в Питон“, вернее добавить статическую типизацию. Язык Питон очень хорош для написания простых программ с небольшим количеством ветвлений, но в кровавом энтерпрайзе со временем система разрастается, программы усложняются, обрастают if-ами, обработками ошибок, сложным наследованием… И вот тогда отсутствие статической типизации даёт о себе знать. Появляются неожиданные падения, ошибки, программу становится трудно анализировать.


Да, можно использовать „фашистские“ правила кодирования, два-три разных линтера, "import typing“, писать километры тестов, cython, mypy (который, кстати, через запуск показывал предупреждение в одном моём скрипте, чем страшно меня удивил) и т.д. Но все эти меры паллиативны, убивают скорость и простоту разработки.


Почему бы не рассмотреть другие языки? Посмотрим же, что нам нужно от замены: лёгкость среды, те же платформы, где блистает Python, статическая типизация с выводом типов. Хотя кого я обманываю? Всем понятно, что выбранный для проекта язык в первую очередь зависит от компетенций команды, стандартов компании и т.д. Тем не менее, за сравнение вроде бы не бьют?


Давайте сформулируем, что же мы хотим от этого „заменителя Питона“. В качестве обязательных условий возьмём:


  1. Близость семантики к Питону.
  2. Компилируемость. (если уж типы проверяем, почему бы и не докомпилировать?)
  3. Вывод типов. (иначе можно взять cython)
  4. Желательно побыстрее, но это не критично. (где критично, там пишут библиотеки для Python на C).
  5. Хочется не терять „лёгкость“ Python – скорость разработки, быстроту выполнения „Hello world“ов (меня, лично, раздражают скрипты на 3 строки и пол минуты загрузки).
  6. И, конечно, общая приспособленность для „кровавого ынтерпрайза“ — хорошая поддержка разной сложной бизнес-логики и прочего ужаса.

Если мы посмотрим на какой-нибудь рейтинг языков, например TIOBE или PYPL, мы увидим, что из более-менее популярных подходят Rust, Swift, Kotlin. Увы и ах, но Rust не имеет сборщика мусора, Swift не кроссплатформен, Kotlin требует jvm. Мотаем дальше!


Во второй десятке PYPL мы находим Haskell – это уже ближе, хотя Haskell ленивый, чистый, но он со сборщиком мусора, native code, доступен более-менее на тех же платформах, что и Python. Но вот пятый пунктым Haskell не вышел — в его сообществе как-то принято считать, что пользователь всегда может чуть-чуть подождать. Конечно есть Clean с его великолепной эргономикой (0.1 сек на сборку „Hello World“), но сообщества вокруг него, к сожалению, нет. В общем, за медлительность и ленивость отказать, но Хаскель всё-таки стоит записать в маленькую чёрную книжечку.


Условно „промотав дальше“ мы найдём OCaml – вот этот язык уже значительно ближе к Python, чем Haskell. Собственно говоря, OCaml имеет все вышеперечисленные свойства, плюс, в отличие от Haskell, здесь почти нет монад (ну, если „на шкаф не залезать“). По пятому пункту полный зачёт — творцы из Инрии маниакально относятся к производительности компилятора, он получается даже быстрее Клина.


Сравнение языков


Итак, что же у нас есть из возможностей Python, а чего нет? Если просто взглянуть на две программы на этих языка станет очевидно одно – у них катастрофически различается синтаксис, „они похожи друг на друга, как мел и сыр.“ Кроме того, как известно, Ocaml — это функциональный язык, а Python — императивный и, вдобавок, объектно-ориентированный. Фиаско?


К счастью, оба языка не являются „ортодоксальными“ представителями своих семейств, поддерживая и другие парадигмы. В Ocaml'е есть объектно-ориентированная подсистема, и он допускает императивный код, а Python содержит ряд возможностей характерных для функциональных языков (кортежи, анонимные функции, функции высших порядков и т.д.). Посмотрим, достаточно ли этого для полноценной замены.


Так что там с императивностью в „функциональном языке“? Ну, во-первых, в отличие от Haskell в Ocaml есть побочные эффекты и даже оператор „точка с запятой“. Поэтому вполне можно награфоманить


let () =
    begin
        Printf.printf "Hello ";
        Printf.printf "world!\n"
    end

Имеются стандартные циклы for и while. Правда „верблюжий“ for слегка отличается от цикла for в Python. Но это лишь потому, что for в Python „шагает не в ногу“ — это же ведь foreach.


Есть в Ocaml и ссылки — тип ref, позволяющие создавать ну совершенно императивный код, императивнее некуда:


let factorial n =
    let z = ref 1 in
    for i = 1 to n do
       z := !z * i
    done;
    !z

И тут скептически настроенный читатель спросит — что же, теперь везде ставить эти галочки!?! Ну конечно же нет, в Ocaml есть и приветствуется name shadowing или переиспользование имён (в отличие от Haskell). Поэтому, если бы в Python мы хотели написать


def quad_sqr(r):
    r = 2*r
    return r*r

в Ocaml мы напишем


let quad_sqr r =
   let r = 2*r in (* тут мы переиспользуем имя, а не присваиваем! *)
   r*r

То есть, код получается в „псевдоимперативном“ стиле — вроде бы мы и не изменяем ничего, а по смыслу мы как бы и делаем присвоение (знакомые с компиляторами вспомнят про SSA форму, в которую переводится и C++ в clang, и Rust). Причём мы же можем и тип поменять! То есть, поведение при name shadowing получается очень похожим на Python, где мы тоже можем написать


...
x = 1
x = "uno"
...

...
let x = 1 in
let x = "uno" in
...

Кроме того, в Ocaml, как и в Python, нет не только функции Main, но даже и символа Start. Выражения верхнего уровня просто начинают выполняться сверху вниз, как будто интерпретатор их обычным образом читает.


В результате, cтруктура программ на этих языках очень похожа. И там, и там сперва подключаются библиотечные модули, а затем идёт список последовательно вычисляемых выражений. Правда, в Ocaml функции — это тоже значения, поэтому их нельзя вызывать до того, как они вычислены, то есть выше по тексту, а в Python можно. То есть, в Ocaml нужны небольшие указания компилятору, чтобы из функции f вызвать g, если текст g расположен ниже (то есть, функции взаимно рекурсивные).


Поскольку структура небольших программ на этих языках очень похожа, зачастую можно просто механически перевести с одного языка на другой:


import os

x = 8

def f(z):
   return z + x

print(f(2))

open Unix

let x = 8

let f z = z + x

Printf.printf "%d\n" (f 2)

Как вы уже заметили, типы я нигде не указывал. Это потому, что указывать их и не нужно — система типов позволяет выводить их почти всегда. Не сказать, что это так уж замечательно всегда и везде, но это факт. Кто не верит, может убедиться почитав исходники компилятора, например https://github.com/ocaml/ocaml/blob/trunk/typing/patterns.ml Заодно, кстати, станет понятно, где же у вывода типов тёмная сторона.


И там, и там есть объекты. Правда в OCaml их не любят, а в Python обожают. Если честно, мне кажется, что в кровавом энтерпрайзе могли бы немножечко и перестать приносить жертвы богам ООП.


Зато в Ocaml есть и широко используются модули! Благодаря прекрасному разработчику по имени Alain Frisch они даже могут быть значениями! Почти как в 1ML. Причём модули могут быть параметризованы, то есть, это функции над модулями (в Ocaml они называются функторами). Таким образом, модули слегка дублируют объекты, а значит и в Ocaml тоже можно реализовать огромное количество примеров из книги четырёх.


И да, кровавый энтерпрайз функторы в Ocaml любит точно также, как классы в Python. И тоже злоупотребляет.


Различия


Меня всегда удивляло, что многие знатоки Python относят списковые включения (list comprehensions) к „нефункциональному стилю“, подразумевая под функциональщиной map, filter и прочие функции высших порядков. Всё-таки, даже в ортодоксально функциональных языках вроде Miranda есть и то, и другое.


А вот в Ocaml этих самых list comprehensions нет. Совсем нет, да и не было никогда. Зато там есть функции высших порядков вроде List.map и анонимные функции, а также стащенный из Haskell оператор ($) превратившийся в очки (@@).


Кроме того, в Ocaml есть алгебраические типы и прекрасно разработанный и оптимизированный pattern-matching со всеми прелестями:


match (price, quantity) with
| (None, _)                -> 0.0
| (Just x, v) when x > 0.0 -> x *. v
| (Just x, _)              -> failwith "negative price"

Зато, как вы могли заметить, в этом чудесном отрывке, манящим нас в мир корректной бизнес логики, есть один странный оператор, вот этот — (*.). Очень похоже на умножение, но зачем там ещё точка? Увы и ах, но это результат отсутствия классов типов (traits в Rust) — отдельный оператор умножения чисел с плавающей точкой. То есть, для целых в Ocaml у нас есть обычные +-*/, а для „вещественных“ вот этот ужас: +. -. *. /


Конечно, если нужно писать большое количество формул, то можно просто переопределить операторы +-*/. Но это всё равно неудобно. Увы, такова плата за строгую типизацию без классов типов.


Также без классов типов нет очень важного — простого интерфейса отладочной печати, то есть питоновского „print“. Конечно, есть масса разных реализаций с помощью препроцессоров PPX, но это всё не то. Гораздо проще было бы, позволяй компилятор генерировать функции toString и print. Причём, что очень обидно, компилятор умеет генерировать бинарные представления любых объектов — см. модуль Marshal.


Таким образом, Ocaml всё же неидеальная замена Python. Главных недостатков два: нет классов типов и удобной отладочной печати любых структур.


Экосистема


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


Компиляторы и интерпретаторы


Начнём, разумеется, с главного, с того, что вообще позволяет работать с языком не только в тетрадке — с компиляторов/интерпретаторов. Для Python'а существует масса интерпретаторов, включая интерпретаторы с JIT, все они на слуху, но основной, конечно, это cpython. В Ocaml всё значительно беднее, собственно компилятор и интерпретатор существуют в единственном экземпляре, github:/ocaml/ocaml.git, продукция Научно Исследовательского Института Inria.


Есть разные вариации этого компилятора, подточенные под разные ситуации (фирмы Lexifi, OcamlPRO, Facebook и д.р.). Основные целевые архитектуры компилятора — x86, ARM и POWER. Относительно недавно вместо MIPS добавлена архитектура RISC-V.


Вместе с компилятором в поставке Ocaml идёт интерпретатор байткода, ocamlrun. Скорость интерпретации примерно такая же, как у интерпретатора Python без JIT. Зато, ровно также как и Python интерпретатор Ocaml может работать на всём, на чём можно скомпилировать C-шный код.


Таким образом, компилятор в машинный код у Ocaml есть примерно на тех же плаформах, где у Python есть интерпретаторы с поддержкой JIT. А простой интерпретатор работает более-менее везде, хотя и с ограничениями. Самой-самой-самой основной целевой платформой Ocaml, как для Python'а, является Linux/x86-64. Таким образом, тут мы можем констатировать идеальную замену.


Библиотеки


Набор библиотек, с одной стороны, относительно скуден и изначально заточен под нужды компиляции, но с другой стороны, есть всё необходимое (по крайней мере мне).


Так для работы с JSON есть yojson, для асинхронного кода — lwt или async, для YML — yml, для тестирования — OUnit/OUnit2/QCheck и т.д. Если чего-то не хватает, но есть Cшная библиотека, можно сделать обёртку для подключения с помощью FFI (Foreign Function Interface), затратив примерно столько же времени, сколько стоит обёртка для Python'а.


Кроме того, есть же JaneStreet, давно работающая с Ocaml в совершенно разных областях с совершенно разными задачами. Поэтому можно воспользоваться библиотеками этой конторы, правда они сильно связаны друг с другом.


Отдельное слово стоит сказать про стандартную библиотеку. Она традиционна весьма бедна и консервативна. Тем не менее, за последнее десятилетие она подросла до более-менее разумного охвата. Разумеется, есть альтернативные стандартные библиотеки, в частности JaneStreet Core, batteries, ExtLib.


Посмотреть на доступные библиотеки можно тут — https://opam.ocaml.org/packages/


Системы сборки


Следующий важный инструмент — это система сборки. И тут, конечно, у Ocaml царит жуткий зоопарк. Складывается ощущение, что система сборки — это, что каждый программист на Ocaml обязан написать. К счастью, на данный момент вроде бы нашёлся „победитель“ — это система Dune. Несмотря на ряд недостатков, обусловленных происхождением из кровавого энтерпрайза с Wall Street, она имеет и ряд достоинств — потрясающую скорость, чудовищную масштабируемость, (в частности умение собирать сразу тучу проектов максимально быстрым образом), постоянные обновления для поддержки всего нового и прогрессивного.


Поэтому в большинстве проектов используется именно Dune, но (помним про кровавый энтерпрайз) с обвязкой в виде простого Makefile для удобства (например https://github.com/ocaml-community/sedlex/blob/master/Makefile ).


У Python, говорят, тоже есть какие-то сборки. Но любим мы его ведь не за это? Поэтому перейдём к следующему акту Марлезонского балета.


Пакетные менеджеры


И у Python, и у Ocaml есть пакетные менеджеры. У Python это pip, а у Ocaml — это OPAM (http://opam.ocaml.org). Оба менеджера предоставляют примерно одинаковые базовые возможности, но pip позволяет создавать пакеты wheel, а OPAM имеет механизм switch (позволяет использовать разные компиляторы с разными наборами установленных пакетов, для проверки под разными версиями экосистем).


Конечно, напрямую механизм wheel копировать в OPAM нет необходимости — можно ведь распространять бинарные скомпилированные программы (с байткодом, увы, это не получится — интерпретатор читает магическое число у программ и не запускает те, что были собраны с компилятором другой версии). Но, надо отметить, что очень не хватает в репозитории OPAM срезов длительной поддержки (для знатоков экосистемы Haskell, OPAM реализует hackage, но не реализует stackage). Отсутствие LTS срезов мешает делать автоматическое пакетирование программ и библиотек Ocaml в дистрибутивах Linux. Будем надеятся, что его всё-таки реализуют.


Линтеры и авто-форматирование, поддержка в IDE и прочее


Тут просто — доведённых до ума линтеров в Ocaml нет, а ocamlformat есть. Поскольку в сообществе особого орднунга нет, в природе наблюдаются несколько разных более-менее стандартных настроек этого ocamlformat. Поскольку язык компилируемый, всё очевидно и просто.


Вопрос с линтерами не закрыт отчасти потому, что они не особо и нужны. С одной стороны, язык компилируемый, поэтому на неиспользуемые переменные укажет компилятор. С другой стороны, язык значительно проще, чем С++, поэтому из предупреждений PVS-studio релевантны для Ocaml ну дай бог 5% (всякое связанное с булевскими операциями и одинаковыми ветками match/if).


Поддержка Ocaml в VSCode есть, причём достаточно хорошая. Дело в том, что ещё до появления стандарта LSP для языка Ocaml были разработаны плагины для Vim и Emacs, реализующие, грубо говоря, Intellisense. Поэтому существующая пара реализаций LSP для Ocaml умеют показывать выведенный тип переменных и выражений, компенсируя тёмную сторону Хиндли-Милнера.


Подсветка синтаксиса Ocaml есть, в целом, везде, где есть, скажем Cшная (кроме Хабра, конечно).


Документация генерируется с помощью двух утилит — старой ocamldoc и модной молодёжной odoc. Они совместимы по языку разметки комментариев, немного напоминая Doxygen, с которого вроде бы все и пошли. Или от чего-то другого?


В минимальной поставке компилятора включены базовые инструменты для генерации парсеров — Ocamllex и Ocamlyacc. Это, творчески сделанные порты lex и yacc (bison). В принципе, если вы по какой-то причине собираетесь сделать парсер для C/С++ на flex/bison, настоятельно рекомендую сделать сперва прототип на Ocamllex/Ocamlyacc, а потом его портировать на пару flex/bison. Такой подход убережёт от огромного количества проблем, т.к. Ocamllex/Ocamlyacc генерируют полностью типизированный код, который проверяется компилятором от и до.


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


Развитие и люди


По сравнению с Python, Ocaml развивается значительно расслабленнее, сдержаннее и совместимее с собой. Программы 90х, использующие только Stdlib, скорее всего придётся совсем совсем слегка подработать напильником, но программы десятилетней давности будут работать как есть. Как правило, место приложения напильника и угол подпилки очевидны из выданных компилятором ошибок.


Неторопливость проявляется, например, в том, что очень интересная оптимизация TRMC (Tail Recursion Modulo Constructor) добралась до кода через 6 (шесть) лет после того, как её предложили. С другой стороны, вот вот уже появится „локальный термояд“ — близко завершение проекта Ocaml Multicore, реализующего „нормальную“ поддержку многопоточности. В общем, движение есть, прогресса… тоже есть.


С людьми в Ocaml всё обстоит сильно иначе, чем в Python'е. Толп нет, но народ присутствует. Как правило, программисты на Ocaml умеют писать на C и догадываются о наличии других языков программирования. То есть, относительно квалифицированы. :-)


В ряде мест Ocaml и родственный ему SML используются для обучения студентов программированию. В принципе, семантика Ocaml значительно интуитивнее, чем семантика Python — ядро языков семейства ML изложено с примерами на буквально 40 страницах „Введения в Стандартный ML“ Р. Харпера. Полная сводка синтаксиса — https://ocamlpro.github.io/ocaml-cheat-sheets/ocaml-lang.pdf


Ocaml считается наиболее удобным языком для построения компиляторов, поэтому он популярен среди компиляторщиков, особенно из Франции. Слово программа в переводе на французский пишется logiciel, и это не просто так: Ocaml широко применяется для разработки разных инструментов верификации, доказательства и т.д.


Другая часть сообщества — это любители Web, уставшие от JavaScript'а. Мне трудно судить, насколько это направление перспективно, но люди есть и что-то делают. Ключевые слова — bucklescript (транспайлер из Ocaml в JavaScript, генерирующий высококачественный код) и ReasonML — альтернативный синтаксис для Ocaml.


Третья часть — это Jane Street, где Ocaml пытаются воткнуть буквально везде. И хотя они открыли достаточно большое кол-во крайне полезного кода, их библиотеки — это немножко „кубик-рубик-монолит“. Просто по структуре и целям „кровавого энтерпрайза“ как-то само собой получается, что все библиотеки стремятся слепиться в единый ком. Разумеется, их можно упорядочить и разделить, но это отдельная деятельность, которой, как правило, занимаются когда уж совсем допекло.


Основное место общения людей из разных областей сейчас — https://discuss.ocaml.org/
и Github.


Основной сайт языка — https://ocaml.org
Сборник документации — https://ocamlverse.github.io/


Заключение


Таким образом, Ocaml вполне подходит для замены Python в разработках программ со сложной бизнес-логикой несмотря на некоторые недостатки.


Решающий плюс — развитая система алгебраических типов данных, включающая GADT и Polymorphic Variants (алгебраические типы без объявления), и отлично проработанный быстрый pattern-matching.


Никакие линтеры не позволят языку с динамической типизацией получить то, что имеет язык со статической типизацией „по праву рождения“. Увы и ах, но если язык позволяет подменять методы классов, этим неизбежно будет кто-то абсолютно легитимно пользоваться. И никакой линтер не способен изменить решения человека, написавшего вон тот библиотечный код 5 лет назад.


Серьёзные минусы Ocaml — отсутствие классов типов вообще и класса Show в частности. Да, есть возможность используя разные PPX реализовать относительно лёгкую отладочную печать, но это неудобно. С моей точки зрения, даже в Haskell нужно вставить обязательную генерацию какого-нибудь DebugShow для всех объектов вообще. А про Ocaml тут и говорить нечего.


Поэтому, конечно, не надо рассматривать эту статью как призыв бежать и менять Python на Ocaml везде и всюду. Да, статическая типизация в больших системах помогает, но есть ситуации, когда нам лучше, чтобы программа даже не была корректной, а уже как-то запускалась. Характерный пример — Wolfram или Jupyter notebooks. Согласитесь, если бы для вычисления какого-то выражения в них требовалась корректность всех ячеек, это была бы просто боль.


Тем не менее, когда разрабатываемая система содержит огромное количество ветвлений, её функциональность нельзя покрыть тестами из-за комбинаторного взрыва. Да и тесты далеко не бесплатны (бесстыдно занимаюсь самоцитированием — https://habr.com/ru/post/560370/ ). И тогда возникает время переходить к статической типизации.


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

Комментарии (17)


  1. amarao
    09.12.2021 17:36
    +2

    Сколько бит в int'е у OCaml? Я думаю, после ответа на этот вопрос окамл можно закапывать, потому что это решение неортодоксальное, а в ряде применений - глупое.


    1. vkni Автор
      09.12.2021 17:54

      Сколько бит в int'е у Python'а? :-)


      1. amarao
        09.12.2021 17:56

        Бесконечность, memory bound. А вот 30 (62) у OCaml - это странно и для питониста, и для сишника.


        1. vkni Автор
          09.12.2021 18:01

          Какая разница 31 или 32 зуба в сравнении с БЕСКОНЕЧНОСТЬЮ?


          1. amarao
            09.12.2021 18:04

            Оказывается, что есть. Например, если вы работаете по сети и у вас ходят 32\64 битные пакеты и вы хотите с ними делать разумные битовые операции. Если бы у вас было 31 (для signed int) или 63, то вы с лёгкостью всё реализуете. Если у вас на 1 бит меньше, бездна раскрывается.


            1. vkni Автор
              09.12.2021 18:19

              FFI в помощь, Int32/Int64 в хату. :-)


              1. fougasse
                09.12.2021 18:25

                Но зачем эти грабли и костыли на ровном месте, если реальность такова, что в int таки кратно октету в подавляющем большинстве случаев?


                1. vkni Автор
                  09.12.2021 19:04

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


    1. funca
      09.12.2021 19:26

      Хорошо, что про юникод ещё не спросили.


  1. iskateli
    09.12.2021 18:19
    +1

    Если бы в Julia сделали бы полноценную статическую типизацию, то это было бы замечательно. Что мешало им сделать Джулию статически типизированной? И опционально добавить dynamic как в C# например.

    Джулия очень универсальная, считай почти что это Лисп с его лозунгом «Лучше иметь 100 функций, которые работают с одной структурой данных, чем 10 функций работающих с 10 структурами».

    Главное – это именно multiple dispatch в сочетании с опциональной типизацией и выводом типов. Это позволяет решить expression problem (https://en.wikipedia.org/wiki/Expression_problem – The goal is to define a datatype by cases, where one can add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety (e.g., no casts)) – отдельно пополнять алгоритмы и структуры данных, причём не теряя в производительности и не залезая внутрь уже имеющегося кода. Это ключ к модульности, платформенности, созданию библиотек. Пополнить код новыми типами данных и процедурами можно без перекомпиляции уже имеющихся библиотек и потери в производительности, в этом фишка. И не путайте multiple dispatch с перегруженными операторами, это не про синтаксис вообще!

    Это типа засунуть концепт базы данных внутрь языка: позволить писать алгоритмы, которые не нужно потом менять по мере постепенного раскучерявливания структур данных. Особенности обработки новых структур данных можно просто добавлять, как программы обработки данных в базах данных. С другой стороны, можно добавлять процедуры – это как засунуть базу процедур внутрь языка, симметричная базам данных идея, которая должна бы использоваться при распухании не данных, а кода.

    https://ailev.livejournal.com/1218155.html


    Я не знаю ни одного языка, который бы так близко приблизился к решению проблемы Expression problem.


    1. alec_kalinin
      09.12.2021 18:43

      Все бы было хорошо в Julia с multiple dispatch, если бы не проблема Time to First Plot. Грубо говоря, каждый независимый запуск Julia скрипта занимает кучу времени, пока все multiple dispatch зависимости соберутся.

      В форум Julia люди постоянно приходят с такими проблемами. Вот, например, человек решает Julia PDE. Время первого вызова на Julia на суперкопьютере 15 часов!!!

      За это время на Python можно уже найти актуальную проблему, ее решить, привлечь инвесторов, сделать стартап и успехом его продать. И это пока Julia только первый вызов пытается выполнить.


  1. V1tol
    09.12.2021 18:23
    +2

    Увы и ах, но Rust не имеет сборщика мусора

    Вот здесь облился чаем и полюбил Rust ещё больше

    Swift не кроссплатформен

    На линуксы тулчейны уже несколько лет доступны, даже для десятки можно скачать.


  1. thegriglat
    09.12.2021 18:35
    +2

    Странно, что про Nim ни слова

    Имхо максимально близкий к питону синтаксис, но сам не компилируется, по сути компилятор Nim это транслятор в C, JS и что-то там ещё (забыл), которые уже компилируются как разработчик этого хочет

    Язык, конечно, не шибко популярный, со своими "приколами", но достаточно зрелый для рассмотрения


  1. snp
    09.12.2021 19:12
    +1

    Ну и https://crystal-lang.org/, конечно же, который похож на Ruby, но компилируется. Уже версия 1.2.2 вышла.


  1. funca
    09.12.2021 19:19

    Ключевые слова — bucklescript

    Теперь уже ReScript, с поддержкой JSX. Позиционируют как альтернативу Typescript. Я так вижу в Фейсбуке любят ФП, и готовы хоть каждый год сочинять по компилятору, но снаружи ни кто не понимает - за что.


  1. koldyr
    09.12.2021 19:32

    А я вот за хаскель расстроился. Понимаю, что чего-то не знаю. Но очень хочу увидеть трехстрочник с трехмтнутной компиляцией.


  1. evgenyk
    09.12.2021 19:33

    Мне кажется, что нужно не искать замену Питону, в виде языка со статической типизацией. Есть реализации питона со статической типизацией. Напримур Cython. Он решает две чаще всего называемые проблемы питона, добавляет статическую типизацию и скорость. Но не взлетает.

    Осмелюс прдположить, что востребован именно язык с динамической типизацией.
    А необходимость статической типизации в языке с областью применения питона это просто такой распространенный миф. Был бы нужен такой язык, давно бы уже взлетел или cython, или один из конкурентов со статической типизацией.

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

    Для того же, чтобы писать на питоне программы со сложной логикой необходи другой стиль программирования. Регомендаций не просите, я не готов их дать.
    Скажу только, что за время работы разрабочиком питона никогда пролемой для меня не была проблема с типами. Возможно я не сталкивался с такими областями, где это стало бы проблемой, но все-таки.