> -- Comdiv писал(а):
> Интересно, как они скомбинировали функциональность, то есть, работу с неизменяемым состоянием, и стековость, то есть, работу с изменяемым глобальным состоянием - стеком.Программа на любом, даже самом чистом функциональном, языке программирования будет иметь некое "глобальное состояние" в процессе своего исполнения. Насколько я понимаю, суть функционального программирования в том, чтобы результат работы фукнции зависел только от её параметров и не зависел от каких-то посторонних изменяемых "глобальных переменных", файлов, ввода пользователя или текущей даты на календаре. В этом смысле стек в Факторе - это только лишь параметры функций, а не набор глобальных переменных с произвольным доступом. Каждая функция имеет доступ только к тому количеству элементов стека, которое указано в её объявлении, и должна оставить на стеке соответствующим образом объявленное число выходных параметров. Другими словами, стек в Факторе - это не структура данных, а способ организовать вызов функций.

Но, конечно, Фактор не является чистым фукнциональным языком, там и глобальные переменные можно использовать, и текущую системную дату можно получить. Но если этими дополнительными возможностями не пользоваться, то основа будет вполне себе функциональная.

Например, есть функция "map" которая вернёт новый экземпляр массива, а есть "map!", которая попытается заменить элементы в существующем массиве и выбросит ошибку, если тот immutable.

> -- Comdiv писал(а):
> Поясните, пожалуйста, что Вы имеете в виду, ведь Хаскель появился на 13 лет раньше Фактора.Тут я, видимо, сел в лужу, поскольку с Хаскелем никогда особо знаком не был. Мне кажется, я на него тогда поглядел и прошёл мимо. Почему - уже не помню. Может быть, он показался мне слишком сложным, а может быть тогда не было нормальных GUI-библиотек под Windows.

> -- Comdiv писал(а):
> Но выглядит как классический маленький пример кода для произведения эффекта на зрителей, но неприменимого для нормального использования. Например, из этого кода совсем неясно, что он делает, несмотря на родство с обычным языком.Есть тип duration, есть тип timestamp. "days" - это конструктор, который создаёт новый объект типа duration и инициализирует его поле day, в данном случае числом 5. На выходе получаем указатель на объект, представляющий пятидневный интервал. Функция "ago" берёт текущую системную дату в виде объекта timestamp, возвращённого функцией "now", и вычитает из этого времени переданный ей duration. На выходе получаем timestamp, представляющий текущее время минус пять дней.

Не знаю, что сказать насчёт реальной применимости. Скажу, что я был впечатлён проработкой библиотекиcalendarи открыл для себя много нового о календарях и исчислении дат. А не так давно добавил тудафункцию, позволяющую узнать номер недели в соответствии сISO 8601, что бывает полезно для бизнес-календаря. Работает так:
## Код:
```
today week-number .
19
```
Для меня это практичный результат, применимый для нормального использования. Понятное дело, что язык программирования - это особый словарь, и надо понимать, что какие слова делают, и иметь представление о том, какие они там вообще в наличии есть. Это не интерпретатор разговорного английского, отнюдь. Но я заметил, что опытные разработчики умудряются писать на Факторе достаточно интуитивно понятные вещи, в том числе придумывая мини-DSL по ходу дела. Парсер можно расширять библиотечно, добавлять свой синтаксис. Так сделана поддержка регулярных выражений (словоR/), которые компилируются в нативный код, так сделана работа с XML (слова<XML... XML>) и некоторые другие вещи. Я к этому уровню ещё только стремлюсь. Как-то раз попытался добавить в парсер распознавание времени в формате hh:mm:ss, но так и не закончил. Как-нибудь сделаю, тогда можно будет написать 01:15:00 и получить объект duration длиной в один час с четвертью.
https://docs.factorcode.org/content/art ... words.html

> -- Comdiv писал(а):
> Не это ли подразумевалось под функциональностью?Может быть, в том числе и это, хотя обычно этот аспект называют point-free style илиTacit programming.
Мне кажется, что в этом суть конкатенативности, а не функциональности: последовательность (конкатенация) функций есть их композиция (применение следующей к результату предыдущей).

> -- Comdiv писал(а):
> Проверка статическая? Если да, то как создатели этого добились?Да, проверка статическая.

Хм. Может быть, я чего-то не понимаю, но мне так кажется, что если мы знаем стек-эффект всех примитивов (сколько каждый потребляет со стека, и сколько после себя оставляет), то вычислить стек-эффект любой их композиции - задача не сложнее подсчёта баланса скобок в строке. Конечно, там будут особые случаи типа особых требований кинлайновым рекурсивным фукнциям, но в остальном-то всё достаточно просто.

Каждое слово в объявлении указывает свой стек-эффект, компилятор его проверяет, глядя на используемые им слова. Если слово соответствует, компиляция успешна, иначе - ошибка. Без этой минимальной проверки кода, да ещё с утиной типизацией, я вообще не понимаю, как можно что-то разрабатывать. Вот смотрю туториалы от автора языка8thна Ютубе, и просто не понимаю, когда он говорит, что, дескать, вы поначалу будете ошибаться, но потом привыкнете писать мелкими шагами. Не понимаю, как так можно. Проверка стек-эффектов - этоогромноеподспорье для начинающего, да и опытному Форт-программисту, я уверен, не доставляет радости копаться с дампах, чтобы искать, кто испортил стек (особенно потому, что виновник к тому моменту уже закончил работу и исчез).

Библиотечно в Факторе доступна дажепроверка типов входных и выходных параметров,но только в рантайм. Зато обещают, что если типы заранее известны (или уже проверены), то лишние проверки будут удалены при оптимизации.

Всё равно это, конечно, большой минус по сравнению с КП и Delphi - то, что многие ошибки приходится ловить во время выполнения. Даже самые вопиющие случаи, когда порядок параметров перепутан, компилятор проглотит без вопросов. Но, с другой стороны, утиная типизация позволяет писать очень высокоуровневый код и иметь очень абстрактные интерфейсы (скорее, контракты). Авторам Фактора удалось создать довольно большую интерактивную кроссплатформенную систему, которая при этом не только не рассыпается под грузом этой неопределённости, но и остаётся достаточно простой и стабильной в работе, так что я готов им это простить на первое время. Дальше посмотрим.

> -- Comdiv писал(а):
> По опыту использования отмечу и обратную сторону подобных шаблонов. Вместо того, чтобы написать то, что нужно в очевидном виде с ясными подробностями, приходится помнить кучу слов и постоянно уточнять в документации детали поведения, например, происходит ли поиск от начала и до конца, или он происходит в произвольном порядке, что характерно для некоторый типов хранилищ. С плохой памятью - это проблема, без подсказок в IDE сложно сориентироваться. Также, может запутывать ипользование правильных алгоритмов, но с неуместными для конкретного случая названием. Например, до того, как я изучил документацию, меня смутило в ревью требование использования метода стандартной библиотеки HashMap.computeIfAbsent(key, mappingFunction) для случая, когда было необходимо создать и положить элемент в хранилище, если по соответствующему ключу ничего не хранилось. Если трактовать HashMap, как cache вычислений, то название метода становится соответствующим смыслу, но это был не мой случай.Да, чрезмерное количество слов может вносить путаницу, и тут важна последовательность и соглашения. Как я привёл выше, есть слова меняющие и не меняющие объект - "map" и "map!" Аналогично есть "fiter" и "filter!" и другие подобные пары.
Согласованность словаря очень важна, как и сочетаемость слов, а также наличие быстрой справки, полностью с вами согласен. Если в интерактивной среде Фактора написать имя функции (или навести на неё курсор в уже написанном тексте), то в строке состояния отобразится её стек-эффект, а при нажатии Ctrl-h откроется её страница в справке. Оттуда можно по ссылкам идти на общие статьи, перейти к справке по содержащему слово модулю или увидеть близкие по смыслу функции. В общем, из интерактивной среды доступна в точности та же справка, на которую я давал ссылки выше.

Действительно, я иногда ещё забываю, что "[ ... not ] filter" == "[ ... ] reject", но с удовольствием пользуюсь возможностью написать "when" или "unless" вместо "if" с пустой веткой else либо then, соответственно.