1 (изменено: Freeman, 19.09.2023 в 18:22)

Тема: Нетехнологичность функционального синтаксиса (Хаскеля?) для API?

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

В связи с этим есть предположение, что одним из факторов, препятствующих внедрению ФП в массовом производстве, является нетехнологичность синтаксиса типичного функционального языка (Хаскель?) с точки зрения простоты API, затрудняющего, в свою очередь, повторное использования кода. Особенно критично оно для системного программирования.

В промышленном программировании важны прототипы функций, являющиеся неотъемлемой частью интерфейсов библиотек, вместе с типами и констатами образующих модули — отлаженные куски кода для решения типовых задач. Для реальной разработки важно, что в случаях, когда модуль или библиотека не имеют документированного API, то глядя на ее интерфейс (заголовочный файл в Си), легко понять, какие функции в ней содержатся, какие параметры им нужно передавать при вызове, а также типы параметров. Это и есть технологичность. Популярные API служат явным или неявным стандартом решения задач, сокращают время на разработку за счет переиспользования кода.

Переход на ООП не сильно меняет картину или даже упрощает ее, поскольку объявления классов или интерфейсов образуют API естественным образом, а наследование даже добавляет ему выразительности по сравнению с процедурными API. Наверное, поэтому ООП не встретило никаких препятствий при внедрении в массовое программирование.

Синтаксис же функциональных языков часто (?) построен таким образом, что поверхностным взглядом порой трудно понять, какие функции объявлены и доступны вызывающей стороне, какие параметры им передавать. Это затрудняет как повторное использование кода без документации, так и использование кода в качестве самодокументирующегося, тем самым снижая технологичность функциональных языков. Есть предположение, что преодоление этого недостатка сделает функциональное программирование популярней.

Я могу ошибаться, придумав проблему там, где ее нет (типа, Хаскель не подходит для системного программирования, и точка), для выяснения чего и создал тему.

Это спорная тема, модерирование в ней будет жестче, чем в обычных.

Для продолжения дискуссии нужен типичный пример объявления функции на Хаскеле или другом функциональном языке, чтобы показать, присутствует в нем проблема («проблема»?) или нет.

Re: Нетехнологичность функционального синтаксиса (Хаскеля?) для API?

Типичный пример объявлений функций можно посмотреть в справке (первое, что нашлось):

http://hackage.haskell.org/package/base … -List.html

То, что описано как

(++) :: [a] -> [a] -> [a]
head :: [a] -> a
last :: [a] -> a
tail :: [a] -> [a]
init :: [a] -> [a]
uncons :: [a] -> Maybe (a, [a])
null :: Foldable t => t a -> Bool
length :: Foldable t => t a -> Int
map :: (a -> b) -> [a] -> [b]
reverse :: [a] -> [a]
intersperse :: a -> [a] -> [a]
intercalate :: [a] -> [[a]] -> [a]
transpose :: [[a]] -> [[a]]
subsequences :: [a] -> [[a]]
permutations :: [a] -> [[a]]
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
…

это и есть прототипы функций. И для человека, знакомого с Хаскелем, они совершенно прозрачны. Даже не читая описания, например, можно предположить, что

permutations :: [a] -> [[a]]

будет вычислять для некоторого списка список всех возможных его перестановок.


Рассмотрим пример:

map :: (a → c) → [a] → [c]

Как читать такую запись? Все функции в Хаскеле каррированные. Т.е. функция, принимающая два параметра — это на самом деле функция, принимающая первый параметр и возвращающая функцию, которая принимает второй параметр. Поэтому функция map принимает первый параметр типа a → c и возвращает значение типа [a] → [c]. Тип аргумента a → c — это функция, которая принимает некоторое значение произвольного типа a и возвращает значение произвольного типа c. Тип результата функции map:[a] → [c] — функция, которая принимает список элементов типа a и возвращает список аргументов типа c. Или, принимая во внимание каррирование — map принимает функцию, превращающую a в c и список элементов a и возвращает список элементов типа c.

Проще говоря, для типа вида … → … → … → … всё до последней стрелки — аргументы, после последней — результат.

Хаскель умеет выводить типы, поэтому прототип функции часто можно не писать. Но хорошей практикой программирования является явная запись прототипов для экспортируемых модулем функций и опускание их для остальных функций.

Так что с прототипами функций там всё нормально, или я недопонял твою мысль.


Но, на мой взгляд, Хаскель непригоден для системного программирования из-за ленивых вычислений и сборки мусора. Абстракции системного языка должны быть близки к абстракциям машины (как, например, у Си или Паскаля), а для многих функциональных языков (включая мой любимый Рефал) они очень далеки.

Конструкции языка Си напрямую и предсказуемо отображаются на машкоды большинства процессоров. Конструкции функциональных языков требуют дополнительные слои абстракции. Что можно реализовать или интерпретатором байткода, или компиляцией в последовательность инструкций call, что в общем-то будет тем же полускомпилированным байткодом.

3

Re: Нетехнологичность функционального синтаксиса (Хаскеля?) для API?

Маздайщик пишет:

То, что описано как

(++) :: [a] -> [a] -> [a]
head :: [a] -> a
last :: [a] -> a
tail :: [a] -> [a]
init :: [a] -> [a]
…

это и есть прототипы функций. И для человека, знакомого с Хаскелем, они совершенно прозрачны.

А как в Хаскеле записываются перегруженные функции? Или функции, использующие механизм перегрузки в реализации... Вроде это были они. Я то ли в книге Душкина такие примеры видел, то ли где-то еще. За них тогда и зацепился. Нужно будет поискать в архивах, может тексты тех лет и сохранились...

Маздайщик пишет:

Абстракции системного языка должны быть близки к абстракциям машины (как, например, у Си или Паскаля), а для многих функциональных языков (включая мой любимый Рефал) они очень далеки.

Абстракциям каких машин? В учебниках по системному программированию слишком много legacy-определений, на мой взгляд. Они сбивают с толку и не дают увидеть леса за деревьями.

IRL в 2018 году мы видим, что из-за продолжающего работать закона Мура процессоры уже подверглись «фрактализации», а техпроцессы подходят к физическому пределу, то есть ядра будут увеличиваться числом и стремиться к null, выражаясь терминами нашей платформы. Можно продолжать пользоваться legacy-примитивами, но они всё больше и больше будут напоминать программирование баз данных на ассемблере. Что и наблюдается на практике, разве нет?

С программной точки зрения взрывное увеличение числа узлов исполнения должно привести к появлению абстракций высокого порядка, инкапсулирующих в себе понятия процессоров 70-х из учебника Танненбаума. Этот новый инкапсулирующий уровень разве не соответствует функциональной парадигме хотя бы частично?

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

Когда я начинал разработку Кантора, окружающие делали стойку на фразе «компилируемые языки», поскольку для большинства компилируемый язык был один, ну полтора, — C/C++. За это время, слава богу, появились Rust и Go, и теперь о множестве компилируемых языков можно рассуждать спокойно, тебе не отказывают в годности аргументов. Моя гипотеза о ренессансе компилируемых языков оказалась верной.

Примерно то же должно произойти и с целевыми платформами системного программирования, как мне кажется. Первый заход был у Java, он оказался неудачным. Сейчас я издалека наблюдаю за развитием JavaScript и внимательно читаю новости по веб-асссемблеру Wasm. Двоичный веб необратимо изменит ИТ, вам не кажется?

А что касается темы, подождем пока других ответов с примерами API на функциональных языках.