Видеоблогер Конор Хекстра использовал разные языки программирования, чтобы решить одну и ту же задачу. Попутно выяснилось, что у Фортрана полно поклонников.
![](https://habrastorage.org/getpro/habr/upload_files/304/f2e/e30/304f2ee300bbe9916e7aee9ebd7d0943.png)
На YouTube-канале code_report, «посвященном соревновательному программированию», есть интересная работа Конора Хекстры, старшего инженера NVIDIA, работающего над пакетом RAPIDS для конвейеров обработки данных и аналитики. Хекстра увлекается просмотром решений с конкурсов по программированию (LeetCode, HackerRank, Topcoder и Codeforces), а также создаёт видеоролики на близкие к программированию темы, такие как структуры данных и алгоритмы.
У Фортрана оказалось много поклонников
Чтобы исследовать подходы к решению одной задачи на 16 разных языках программирования, Хекстра выбрал относительно простое задание с конкурса программирования LeetCode: определите наименьшее и наибольшее число из заданного списка, а затем найдите их наибольший общий делитель.
Языки, выбранные для решения:
C++
Rust
D
Clojure
Ruby
Elixir
Raku [Perl 6]
Haskell
Racket
Julia
Python
APL
J
BQN
Pharo Smalltalk
Fortran
(В видео поясняется, что последние два языка были добавлены по просьбам зрителей. «Я сделал опрос в Твиттере, и Fortran получил целых 27 лайков!», — объясняет Хекстра. Так что пришлось его тоже включить).
Кардинальные различия
Хотя исходная задача была простой, подходы к её решению в разных языках сильно отличаются. Особенно при переходе на язык массивов. Там подход будет принципиально отличаться от того же Python или Ruby.
Так, в Python уже есть встроенные функции для всех необходимых операций: для нахождения наименьшего числа, наибольшего числа, даже для «наибольшего общего делителя».
![](https://habrastorage.org/getpro/habr/upload_files/0a2/9f1/2e6/0a29f12e66d2a91807b95af8585eb3df.png)
Но всё стало выглядеть абсолютно по-другому, когда Хекстра добрался до функционального языка Haskell. Его функция liftM2
отображает значения минимума и максимума для входных данных функции gcd
— и все это в одной строке.
И самое главное, поскольку Haskell использовал стиль программирования “Tacit” или point-free (стиль программирования без промежуточных переменных, предполагает использование конвейерных функций и комбинаторов), который не указывает аргументы в определениях функций, решение Haskell даже не нуждалось в упоминании массива чисел.
![](https://habrastorage.org/getpro/habr/upload_files/36e/7f7/4e4/36e7f74e421c59e594d4f6cc7af3e8ed.png)
Низкоуровневый язык программирования D требует, чтобы функции были импортированы. Но он хотя бы использует универсальный синтаксис для вызова функций знакомым методом из объектно-ориентированного программирования. Хекстра посчитал это довольно милым.
![](https://habrastorage.org/getpro/habr/upload_files/ba9/0b7/bc8/ba90b7bc86d496004b50b358540bca6b.png)
Хекстра жаловался, что в Rust и в C++ слишком много «формальностей». Обе функции, и min, и max, требуют использования iter()
для прохождения итераций по каждому значению в списке чисел, и unwrap()
для извлечения значения из более сложного модуля Result, который включает информацию об обработке ошибок.
И, как заметил Хекстра: «чтобы получить доступ к функции gcd приходится преодолеть кучу лишнего в пространстве имён num::integer::
. Но в остальном это очень хорошее решение».
![](https://habrastorage.org/getpro/habr/upload_files/a66/86e/36c/a6686e36cb2fb6c39909eebbb29eb5cc.png)
Так как Хекстра является поклонником языков программирования массивов, в его исследовании нашлись и более существенные различия. Решение в APL (справа от розовой стрелки) состоит всего из пяти символов. (Первые два символа находят максимальное значение, последние два символа находят минимальное значение, а зеленая буква v в середине находит их наибольший общий делитель.)
![](https://habrastorage.org/getpro/habr/upload_files/106/d14/a84/106d14a84d7abb7916c394b5a27b82af.png)
Похожая структура есть и в языке программирования J (ещё один язык программирования массивов, но J является усовершенствованной версией APL, в которой используются диаграммы ASCII, а не символы Unicode»). Функция нахождения максимума представлена здесь символом “>”, а функция поиска минимума — “<”.
![](https://habrastorage.org/getpro/habr/upload_files/daf/fc6/cb2/daffc6cb2fb85193424700ff62874b58.png)
Чем дальше, тем всё более экзотическими становились решения. BQN из семейства APL (согласно APL Wiki) всё ещё является языком, управляемым массивами, но он использует свой уникальный набор символов. Поскольку в нём нет встроенной функции для нахождения наибольшего общего делителя, эта функция должна быть определена в отдельной строке кода.
Хекстра признался, что просто скопировал код из онлайн-источника. Как только функция стала определена в первой строке, появилась возможность вызвать её, как часть решения, во второй строке.
![](https://habrastorage.org/getpro/habr/upload_files/5e3/337/0f8/5e33370f8052aac2cac40ed2571527ec.png)
Соревнование со зрителями
Судя по реакции аудитории, им понравились соревнования языков, и они охотно делились собственным опытом.
“Некоторые интересовались решением для Cobol, так что я решил попробовать свои силы: https://t.co/Pi7OSCdeIl Всего-то 91 строка…”
На данный момент видео получило сотни комментариев, в которых предлагались лучшие варианты решений.
Решение на языке Julia был похоже на решение для Python, только с оператором «splat
» (в данном случае троеточие), означающим, что будет проверено более одного значения:
![](https://habrastorage.org/getpro/habr/upload_files/f12/47c/37c/f1247c37c0a3f3eef5874ba3deb719d8.png)
Но зрители предложили более простой синтаксис. В Julia есть две встроенные функции поиска минимума и максимума, которые не требуют многоточия. Также есть одна функция, которая возвращает оба значения “extrema”. А затем решение стало еще проще, когда Хекстра взял оператор склеивания функций для создания point-free решения (с функцией сбора, преобразующей два значения в формат списка, который можно передать в gcd
).
![](https://habrastorage.org/getpro/habr/upload_files/f00/aa1/154/f00aa1154ddd27ac99f8365af1af6b27.png)
«На мой взгляд, это самое красивое решение из всех, — добавил Хекстра — отчасти потому, что оно демонстрирует элегантность point-free решений.»
Затем зрители предложили ещё несколько изящных улучшений для решения Хекстры на Raku (язык, ранее известный как Perl 6). В Raku gcd
— это «инфиксная» функция, которую можно поместить между двумя значениями аналогично математическим операторам (например, плюс или минус). И тогда два значения, между которых его поместили, могут быть результатами методов объектного стиля, вызываемых массивом чисел.
![](https://habrastorage.org/getpro/habr/upload_files/8f2/56f/046/8f256f046a824b23fc252694e981b3f1.png)
По иронии судьбы, решение Pharo Smalltalk оказалось похожим на решение Raku (со своей собственной функцией gcd:
, которая появлялась как «инфиксный» оператор между двумя функциями, возвращающими минимум и максимум).
![](https://habrastorage.org/getpro/habr/upload_files/4b2/856/9f9/4b28569f917a3887dab13d4ea417bd74.png)
Но зрители отметили, что у Raku также есть специальная функция minmax
, которая возвращает оба значения одновременно, что приводит к ещё одному однострочному решению, где этот результат становится входными данными для функции gcd
.
![](https://habrastorage.org/getpro/habr/upload_files/b66/272/f2a/b66272f2add98847e53e250158d15c97.png)
Хекстра счёл такое решение предпочтительным.
По фану с Фортраном
В первом видео Хекстра посчитал решение, написанное на Fortran, худшим, потому что оно тоже было заполнено кучей формальностей и усложнений. Но он уточнил, что «это первый кусок кода на Фортране, который я написал в своей жизни, так что, скорее всего, есть лучшие решения… После 40 минут отладки и запуска этого кода я решил, что пора закругляться».
![](https://habrastorage.org/getpro/habr/upload_files/41d/37a/22b/41d37a22b43eedf26da47b9f80a8ae29.png)
![](https://habrastorage.org/getpro/habr/upload_files/397/ef5/e49/397ef5e49c22ec04836d78da59be948f.png)
Но в последующем видео Хекстра признался, что получил потрясающий ответ от сообщества Fortran. Джейкоб Уильямс, программист Фортрана и орбитальный механик в Космическом центре НАСА имени Джонсона, ответил, что ему для решения задачи потребовалось около 5 минут (с gcd из кода rosetta).
Также видео Хекстры вызвало отклик у Милана Курчича, давнего программиста на Фортране и автора книги «Современный Фортран». Курик поблагодарил Хекстру за включение Фортрана в свой обзор и предложил альтернативное решение, которое включает функцию наибольшего общего знаменателя:
![](https://habrastorage.org/getpro/habr/upload_files/708/557/0fc/7085570fc52416571dac987fb0847ebb.png)
Оказалось, что временная переменная res
не нужна, так как результат можно просто вернуть, не присваивая ему отдельного значения. И некоторые обновления синтаксиса в Фортране теперь позволяют указывать длину списка с помощью одного лишь двоеточия вместо громоздкой переменной numsSize
. Это позволяет избавиться от целой строки кода. Итого вместо огромного кода можно прийти к всего двум строкам в теле функции!
Официальный канал Fortran в Твиттере даже ретвитнул первоначальный твит Хекстры с видео, с комментарием, что они собираются работать над улучшением своих учебных пособий в будущем. По мнению инженера, именно так должно работать сообщество, если оно хочет привлечь новых людей к своему языку.
Что ещё интересного есть в блоге Cloud4Y
→ Как открыть сейф с помощью ручки
→ OpenCat — создай своего робокотика
→ Как распечатать цветной механический телевизор на 3D-принтере
→ WD-40: средство, которое может почти всё
→ Изобретатели, о которых забыли
Подписывайтесь на наш Telegram-канал, чтобы не пропустить очередную статью. Пишем только по делу. А ещё напоминаем про второй сезон нашего сериала ITить-колотить. Его можно посмотреть на YouTube и ВКонтакте.