OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Понедельник, 20 Май, 2019 16:29

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 21 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 12 Май, 2019 13:18 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 846
Откуда: Киев
Александр Ильин писал(а):
Я, конечно, захотел решить задачу на Факторе

Александр, чем Вас заинтересовал этот язык? Что скажете по опыту использования?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 12 Май, 2019 20:08 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2300
Откуда: Россия, Санкт-Петербург
Я хотел изучить что-то экзотичное, но в то же время практичное. Критерии практичности на тот момент (несколько лет назад) критерии были такие: среда должна уметь создавать обособленные исполнимые модули, содержащие консольные и графические приложения, работающие под управлением Windows XP и более поздних версий на 32-битной платформе. Если этого минимума нет, язык не рассматривался, так как ничего полезного для себя я на нём всё равно не смог бы написать (на своём тогдашнем ноуте).

Это было нужно для собственного развития. Мне захотелось понять на практике, что такое функциональные языки программирования, так как до этого я изучал только императивные языки, а о функциональных имел представление на уровне формального определения. Этот пробел хотелось заполнить. Factor мне к тому времени уже подвернулся, презентация на Google Tech Talks произвела хорошее впечатление, а на Википедии было сказано, что язык функциональный, стековый и многопарадигмальный. Это отлично вписалось в идею расширить горизонты моего знания: функциональный - есть, а заодно ещё и стековый, что бы сие ни значило.

Хаскель в те времена ещё только зарождался, Лисп не был практичным по моим критериям, а из прочих языков вообще было не ясно, как выбрать что-то стоящее. Фактор же не только установился и сразу заработал, но и имел богатейшую библиотеку "из коробки", встроенную документацию, интерактивную разработу и многое другое.

Что мне сразу не понравилось после КП и подобных. Текст ошибок, выдаваемых компилятором, иногда не имеет отношения к допущенной ошибке. Эта проблема известна и привычна, я думаю, работающим на C++, но после Delphi и КП есть привычка точно понимать, что пошло не так. В Факторе нет такого строгого синтаксиса, поэтому компилятор сам часто не понимает, что вы от него хотите, от этого взаимный конфуз. В этих случаях приходится переходить на разработку маленькими шагами, чтобы нащупать проблемное место.

Вы спросили об опыте использования. Чтобы мои оценки имели контекст, опишу свой сегодняшний уровень. Я использую Фактор в основном в качестве хобби, для домашних проектов, но иногда пишу и скрипты, которые автоматизируют что-то на работе. За годы знакомства я достиг уровня, когда могу написать средних размеров модуль без ошибок компиляции, но регулярно приходится подглядывать в справку, чтобы уточнить порядок параметров в стандартных функциях или детали их использования. Я работал с GUI (виджеты на OpenGL, таблицы), с файлами, БД (sqlite), многопоточностью (green threads, IPC по TCP), криптографией, делал бинды к сторонним библиотекам (sodium, ...), портировал чужие алгоритмы на Фактор (Ryu). До сих пор не могу сказать, что код на Факторе я напишу быстрее аналогичного кода на Delphi, но я всё ещё надеюсь, что такой переломный момент настанет. В тех случаях, когда в Факторе есть подходящая библиотека (а там их очень много), небольшие проекты удаётся написать за приемлемое время - даже быстрее, чем на Delphi, где надо было бы что-то искать либо изобретать самому.

Пример. Вот скрипт, который можно запустить в корневом каталоге проекта, и он сконвертирует все файлы, у которых нет BOM, из Latin-1 в UTF-8 с BOM.
Код:
! Copyright (C) 2017 Alexander Ilin.
USING:
    io io.directories.search io.files io.encodings.8-bit.latin1
    io.encodings.string io.encodings.utf8 io.pathnames
    kernel namespaces sequences
;

IN: sources-to-utf8

: utf8-signature ( -- str )
    { 0xEF 0xBB 0xBF } utf8 decode ;

: file-to-utf8 ( filename original-encoding -- )
    dupd [ contents ] with-file-reader
    dup "" head? [ 2drop ] [
        swap utf8 [ utf8-signature write write ] with-file-writer
    ] if ;

current-directory get { ".pas" ".inc" ".dpr" ".txt" }
find-files-by-extensions [ latin1 file-to-utf8 ] each
В своих текстовых редакторах я не нашёл такой фукнции пакетной конвертации. Если немного понимать базовые принципы, то код этот достаточно прост и хорошо читается.

Вот пример, который читается не так легко. Это было написать быстрее, чем в очередной раз изобретать проход по подкаталогам в Delphi:
Код:
! Copyright (C) 2019 Alexander Ilin.
USING:
    formatting
    io.directories io.directories.search io.encodings.utf8 io.files
    io.pathnames kernel math namespaces sequences unicode
;

IN: lower-case-extensions

: except-.git ( seq -- seq' )
    [ "/.git/" swap subseq? ] reject ; inline

: (lower-case-extensions) ( path -- )
    [ dup length swap last path-separator? [ 1 + ] unless ] keep
    recursive-directory-files except-.git [
        over tail dup [ parent-directory ] [ file-stem ] [ file-extension ] tri [
            dup >lower 2dup = [ 5drop ] [
                nip "git mv -f %s %s%s.%s\r\n" printf
            ] if
        ] [ 3drop ] if*
    ] each drop ;

: lower-case-extensions ( path batch-file-name -- )
    utf8 [ (lower-case-extensions) ] with-file-writer ;

: run-in-current-directory ( -- )
    current-directory get "lower-case-extensions.cmd"
    lower-case-extensions ;

MAIN: run-in-current-directory

Этот скрипт использует recursive-directory-files для получения списка файлов, начиная с текущего каталога, и создаёт файл "lower-case-extensions.cmd". В результирующем файле содержатся команды git-mv для замены расширения файлов на строчные. Понадобилось, когда увидел, что у нас часть файлов имеет расширение ".Pas" вместо ".pas".

Общее впечатление таково, что при разработке на Факторе я больше времени трачу на "вылизывание" кода, приведение его к наиболее компактному виду, устранению дублирования и т.п. Это доставляет мне удовольствие как решение головоломки. В этом смысле язык, с одной стороны, как раз подходит для хобби, а с другой стороны это просто говорит о том, что я ещё нахожусь в процессе его освоения, раз решения не "выстреливают" из головы сразу. Здесь действительно очень своеобразная языковая модель, и при программировании нужно думать существенно иначе, чтобы писать оптимально. Конечно, никто не запрещает писать в императивном стиле, с локальными переменными, в инфиксной нотации и т.п., но какой в этом смысл? Для меня смысл как раз в том, чтобы взглянуть на привычные и простые задачи по-иному, с совершенно новой точки зрения.

Есть задачи, которые очень легко переносятся из естественного языка на Фактор, и такой код очень легко читается. Например, "5 days ago" - это валидный код на Факторе, который вернёт дату-время за 5 суток до текущего системного времени. Аналогично можно написать библиотеки к любым постфиксным нотациям - "5 cm", "15 m", "20 km", etc., и они будут очень естественно встроены в язык.

Также естественно решаются задачи потоковой обработки данных - например, всё то, что в консоли мы написали бы через пайпы "|", в Факторе записывается точно так же, только через пробелы: применяем одну функцию, результат передаём следующей, и так далее по цепочке. При этом число входных и выходных параметров не ограничено, но строго проверяется компилятором. Без этой последней проверки я вообще не понимаю, как можно написать что-то вменяемое - на том же Форте и миллионе его клонов.

Когда-то очень давно, чуть ли не в школьные или ранние университетские времена, была у меня мысль изобрести некий язык программирования, который бы позволил урезать число потенциальных ошибок до минимума. Что-то вроде библиотеки шаблонов алогоримов над Delphi. Например, нужно нам пройти по массиву от начала до конца, мы берём шаблон прохода по массиву, и внутрь дописываем то, что нам нужно сделать с каждым из элементов. Обычно в Delphi мы применяем некий идиоматичный код типа "for i := 0 to Length(TheArray) - 1 do ...". Проблем с таким подходом много: необходимо уникальное имя для переменной i, саму эту переменную надо где-то объявить, идиома не идентифицируется человеком, который с ней не знаком, в ней можно допустить ошибку, да и вообще, как правило, довольно много текста вокруг нужно прочитать и критериев проверить, чтобы убедиться, что это именно та самая идиома, и что никакие её критерии и правила не нарушены. А если нарушены, то это специально или по ошибке? Не ясно.
Использование шаблона алгоритма решает все эти проблемы, поскольку шаблон однозначно и легко идентифицируется по имени и не даёт нарушить своей структуры, так как структура эта описана в другом месте, а не в месте использования. Кроме того, шаблон может быть улучшен следующим образом: "for i := Low(TheArray) to High(TheArray) do ...". Исправил шаблон - и автоматически новая версия используется везде. Исправить идиому не так просто, особенно в крупном проекте, в том числе потому, что её не всегда легко идентифицировать/найти.

Я с удивлением обнаружил, что в Факторе это всё уже есть и работает. Можно написать любые шаблоны, дать им имя и использовать из библиотек. Например, проход по всем элементам массива (и любой последовательности): "[ ... ] each". Цикл от 0 до X-1: "X <iota> [ ... ] each". При этом анонимной функции внутри [] будут последовательно передаваться значения счётчика от 0 до X-1, и нет ни проблемы с созданием локальной переменной с уникальным именем, ни проблемы с тем, что прикладной код может испортить её значение и сломать цикл, и т.п.

Однако, <iota> - это конструктор неизменяемой виртуальной последовательности с элементами от 0 до X-1.
Код:
! Integer sequences
TUPLE: iota { n integer read-only } ;

ERROR: non-negative-integer-expected n ;

: <iota> ( n -- iota )
    dup 0 < [ non-negative-integer-expected ] when
    iota boa ; inline

M: iota length n>> ; inline
M: iota nth-unsafe drop ; inline

INSTANCE: iota immutable-sequence
Означает ли это, что будет создан экземпляр объекта в динамической памяти, у которого итератором будут вызываться виртуальные методы получения длины и очередного элемента (с проверкой диапазона индекса) и всё это будет дико тормозить? Вот, что думает на этот счёт оптимизирующий компилятор:
Код:
[ 5 <iota> [ drop ] each ] disassemble
00000184779bbe60: 89059a5103ff  mov [rip-0xfcae66], eax  ! Предохраняемся от зацикливания.
00000184779bbe66: b805000000    mov eax, 0x5             ! Число итераций.
00000184779bbe6b: 31db          xor ebx, ebx             ! Обнуляем счётчик цикла.
00000184779bbe6d: 4983c610      add r14, 0x10            ! Какой-то пролог.
00000184779bbe71: e909000000    jmp 0x184779bbe7f (( gensym ) + 0x1f) ! Прыжок на проверку условия выхода из цикла.
00000184779bbe76: 48ffc3        inc rbx                  ! Увеличиваем счётчик цикла.
00000184779bbe79: 8905815103ff  mov [rip-0xfcae7f], eax  ! Предохраняемся от зацикливания.
00000184779bbe7f: 4839c3        cmp rbx, rax             ! Проверяем условие выхода из цикла.
00000184779bbe82: 0f8ceeffffff  jl dword 0x184779bbe76 (( gensym ) + 0x16) ! Если не закончили, возвращаемся в цикл.
00000184779bbe88: 4983ee10      sub r14, 0x10            ! Какой-то эпилог, тут я не спец.
00000184779bbe8c: 89056e5103ff  mov [rip-0xfcae92], eax  ! Предохраняемся от зацикливания.
00000184779bbe92: c3            ret                      ! Выход из функции.
Код, может быть и не такой чистый, как написанный вручную, но суть в том, что все неиспользуемые абстракции удалены. Во все циклы компилятор автоматически добавляет команду записи в определённую страницу памяти. Если программа зациклилась, её можно прервать, пометив эту страницу как read-only. Я лично добавил поддержку Ctrl+Break в платформенный код под Windows по аналогии с BlackBox.

Программа никогда не "зависает" при долгой работе с вводом-выводом, поскольку все файловые операции сделаны через "overlapped", соответственно, другие кооперативные треды продолжают работать, в том числе отрисовка интерфейса.

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

Другой пример полезного класса шаблонов - функции типа with-file-reader: "path encoding [ ... ] with-file-reader". Для сравнения примерный аналог на Delphi:
Код:
var
  f: File;
begin
  AssignFile(f, path);
  ResetFile(f);
  try
    ...
  finally
    CloseFile(f);
  end;
end;
Другими словами, with-file-reader берёт на себя открытие и закрытие файла, в том числе при возникновении исключений внутри пользовательского кода. Очень удобно и компактно. В Факторе много различных with-* на все случаи жизни. Я позаимствовал этот подход, и уже на Delphi стал писать процедуры, которые принимают на вход анонимную функцию и оборачивают её специфичной обработкой исключений или примитивами синхронизации.
Код:
type
  AccessResourceProc = reference to procedure (const Data: TDataRecord);

procedure TClass.AccessResource(Proc: AccessResourceProc; const MaxWaitTime: Cardinal = INFINITE);
begin
  if Mutex.Acquire(MaxWaitTime) then
    try
      Proc(FInternalDataStructure^);
    finally
      Mutex.Release;
    end;
end;

// Usage:
MyClassInstance.AccessResource(
  procedure (const Data: TDataRecord)
  begin
    ... // Handle Data.
  end,
  100); // Wait not more than 100 msec.
При таком подходе и Mutex, и FInternalDataStructure остаются скрытыми от посторонних глаз, и доступ к внутренним данным класса TClass возможен только через синхронизанию. Соответственно, забыть вызывать Mutex.Acquire или Mutex.Release у клиентского кода попросту нет никакой возможности, что повышает надёжность кода.

GUI в Factor организовать труднее, чем в Delphi, это недостаток, который в том числе обусловлен кросплатформенной работой поверх OpenGL (стандартные контролы ОС не используются). Конечно, никто не мешает сделать бинды и пользоваться, но в стандартной поставке этого нет (хотя, что-то там из GTK маячило, но я не вчитывался), зато есть свои собственные контролы и механизмы их расположения на окнах. В целом, очень зрелый инструмент для прикладного программирования, на мой взгляд.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 12 Май, 2019 20:40 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9117
Откуда: Россия, Орёл
Спасибо, Александр, очень интересно!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 12 Май, 2019 22:49 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 846
Откуда: Киев
Спасибо за столь развёрнутый ответ, очень интересно.

Александр Ильин писал(а):
Это отлично вписалось в идею расширить горизонты моего знания: функциональный - есть, а заодно ещё и стековый, что бы сие ни значило.
Интересно, как они скомбинировали функциональность, то есть, работу с неизменяемым состоянием, и стековость, то есть, работу с изменяемым глобальным состоянием - стеком.

Цитата:
Хаскель в те времена ещё только зарождался
Поясните, пожалуйста, что Вы имеете в виду, ведь Хаскель появился на 13 лет раньше Фактора.

Цитата:
Например, "5 days ago" - это валидный код на Факторе, который вернёт дату-время за 5 суток до текущего системного времени.
Но выглядит как классический маленький пример кода для произведения эффекта на зрителей, но неприменимого для нормального использования. Например, из этого кода совсем неясно, что он делает, несмотря на родство с обычным языком.

Цитата:
Также естественно решаются задачи потоковой обработки данных - например, всё то, что в консоли мы написали бы через пайпы "|", в Факторе записывается точно так же, только через пробелы
Не это ли подразумевалось под функциональностью?
Цитата:
При этом число входных и выходных параметров не ограничено, но строго проверяется компилятором.
Проверка статическая? Если да, то как создатели этого добились?

Цитата:
Можно написать любые шаблоны, дать им имя и использовать из библиотек
По опыту использования отмечу и обратную сторону подобных шаблонов. Вместо того, чтобы написать то, что нужно в очевидном виде с ясными подробностями, приходится помнить кучу слов и постоянно уточнять в документации детали поведения, например, происходит ли поиск от начала и до конца, или он происходит в произвольном порядке, что характерно для некоторый типов хранилищ. С плохой памятью - это проблема, без подсказок в IDE сложно сориентироваться. Также, может запутывать ипользование правильных алгоритмов, но с неуместными для конкретного случая названием. Например, до того, как я изучил документацию, меня смутило в ревью требование использования метода стандартной библиотеки Java
Код:
HashMap.computeIfAbsent(key, mappingFunction)
для случая, когда было необходимо создать и положить элемент в хранилище, если по соответствующему ключу ничего не хранилось. Если трактовать HashMap, как cache вычислений, то название метода становится соответствующим смыслу, но это был не мой случай.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 02:27 
Аватара пользователя

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

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

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

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

Comdiv писал(а):
Цитата:
Например, "5 days ago" - это валидный код на Факторе, который вернёт дату-время за 5 суток до текущего системного времени.
Но выглядит как классический маленький пример кода для произведения эффекта на зрителей, но неприменимого для нормального использования. Например, из этого кода совсем неясно, что он делает, несмотря на родство с обычным языком.
Есть тип 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, соответственно.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 05:57 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8089
Откуда: Троицк, Москва
Навыки функционального мышления -- это хорошо.
Обсессия с функциональными брейнфаками -- потеря времени.

(Кстати, рассуждения о стэке звучат подозрительно, но вдаваться не хочу.)

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

По-моему, это было бы более содержательно, чем некоторые иные методические инструменты.

PS
Трурль когда-то констатировал, что для функ. языков не было своего Вирта. По сути речь об этом.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 10:06 

Зарегистрирован: Пятница, 13 Март, 2009 16:36
Сообщения: 793
Откуда: Казань
Info21 писал(а):
Короче, методическая задачка: найти/сделать функ. инструмент, на котором можно было бы "поставить" учням/студням навыки функ. мышления, но при этом остаться в парадигме "единой системы вводных курсов программирования".

Мне кажется, что можно попробовать программировать в функциональном стиле на Обероне.
Что для этого надо?
- Не использовать глобальные переменные;
- Не использовать процедуры, а использовать функции (вместо процедуры NEW для выделения памяти, нужно вызывать функцию).
- Не использовать возврат значений через VAR, а возвращать все значения через результат функции (а так как, например, записи нельзя возвращать как результат функции, то нужно выделять память под запись и возвращать указатель на запись);


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 12:45 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2573
Откуда: Россия, Ярославль
Info21 писал(а):
Короче, методическая задачка: найти/сделать функ. инструмент, на котором можно было бы "поставить" учням/студням навыки функ. мышления, но при этом остаться в парадигме "единой системы вводных курсов программирования".

PS
Трурль когда-то констатировал, что для функ. языков не было своего Вирта. По сути речь об этом.

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

Например, LoLa, как язык декларативного программирования в парадигме Оберонов. Ну или LOMO, если вдруг звёзды сойдутся.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 15:26 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 846
Откуда: Киев
Александр Ильин писал(а):
Программа на любом, даже самом чистом функциональном, языке программирования будет иметь некое "глобальное состояние" в процессе своего исполнения
Верно и обратное - любую императивную программу можно трактовать как чисто функциональную. К примеру, подпрограммы Форта, которые могут менять состояние всего стека можно трактовать как чистые функции, которые принимают на вход один параметр-стек и возвращают новое значение - изменённый стек, которое присваивается новой переменной, затеняющей старую. Но дело-то не в трактовках.

Александр Ильин писал(а):
В этом смысле стек в Факторе - это только лишь параметры функций, а не набор глобальных переменных с произвольным доступом
Если это так, тогда это частично объясняет, как в Факторе добились статической проверки кол-ва параметров. В Форте изменения стека доступны по всей глубине, хотя делать это лишний раз и считается дурным тоном.

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

Цитата:
Есть тип duration, есть тип timestamp. "days" - это конструктор, который создаёт новый объект типа duration и инициализирует его поле day, в данном случае числом 5. На выходе получаем указатель на объект, представляющий пятидневный интервал. Функция "ago" берёт текущую системную дату в виде объекта timestamp, возвращённого функцией "now", и вычитает из этого времени переданный ей duration. На выходе получаем timestamp, представляющий текущее время минус пять дней.
Вот и ожидаешь в обычном коде увидеть что-то вроде:
Код:
5 DateDuration.days Date.backFromCurrent
который выглядит менее человечно, зато не требуя сильно погружаться в контекст. А скорее, ожидаешь увидеть ещё менее человечный вариант
Код:
Date.current 5 DateDuration.days Date.back
но который более обобщённый, ведь отсчитывать дни нужно не только от текущей даты, а на все частные случаи не напасёшься.

Цитата:
Как-то раз попытался добавить в парсер распознавание времени в формате hh:mm:ss, но так и не закончил. Как-нибудь сделаю, тогда можно будет написать 01:15:00 и получить объект duration длиной в один час с четвертью.
Но это ведь тоже пример непрактичности, ведь обычно люди создают функции вроде DateDuration.new(hh:01, mm:15, ss: 00) при этом в принципе невозможно сказать, что я пытался написать такую функцию, но пока ещё не закончил. Как упражнение для ума - вполне, но от нормального кода это надо держать подальше.


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


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 15:32 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 846
Откуда: Киев
Info21 писал(а):
Короче, методическая задачка: найти/сделать функ. инструмент, на котором можно было бы "поставить" учням/студням навыки функ. мышления, но при этом остаться в парадигме "единой системы вводных курсов программирования".
Тоже думал о таком.

Info21 писал(а):
Трурль когда-то констатировал, что для функ. языков не было своего Вирта. По сути речь об этом.
По-моему, об этом говорил один из создателей компилятора Хаскель. Возможно, что это было в одном из номеров журнала Практика функционального программирования

Нашёл то интервью Саймоном Пейтоном Джонсом. Правда, Вирта он не упоминал, но говорил о необходимости уменьшения и упрощения языка
Цитата:
— В чем слабые места Haskell?

—Он сложный. Пожалуй, это его самое слабое место. Думаю, в каком-то смысле он такими задуман. В GHC я хотел реализовать множество фич и посмотреть, как они будут сочетаться и какие понравятся людям. Но в результате, несомненно, получился сложный язык. В некоторых отношениях Haskell прост. Он остался верен своим принципам — чистому функциональному про-граммированию и ленивой стратегии вычислений. Но нынешняя система типов очень сложна. Думаю, самое сложное в Haskell — это то, что это очень большой язык. Надеюсь, однажды кто-нибудь выделит из Haskell лучшие части и соберет из них что-то поменьше. Не знаю, что из этого может выйти. Мы понемногу пытаемся его упрощать, убираем некоторые возможности. В стандартеHaskell 2010 отсутствуютn+k-шаблоны, потому что они в целом довольно избыточны. Мне нравится GHC как платформа для исследований — у него открытый исходный код. Кто угодно может внести изменения. Если у вас есть идея для системы типов или оптимизатора, можете реализоватьее и посмотреть, что получится. Но все же, несмотря на мои попытки переписывания и упрощения, это по-прежнему огромный программный продукт. Многих людей это отталкивает


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 16:57 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1167
Откуда: Украина, Киев
Александр Ильин писал(а):
Например, нужно нам пройти по массиву от начала до конца, мы берём шаблон прохода по массиву, и внутрь дописываем то, что нам нужно сделать с каждым из элементов.
Не выворачивание-ли тут наизнанку одеяла с обычным шаблоном "Посетитель"? Цикл прохода в случае с этим шаблоном и надо-то один раз написать без ошибок, а потом лишь модифицировать "посетителей". Как-то целый проект в таком ключе сделал. Получилась парочка итераторов и вагон и тележка "посетителей" на все ситуации.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 17:08 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1167
Откуда: Украина, Киев
Уменьшение сложности ключевая вещь.
Хоть кто-то из мейнстрима аргументированно изложил, почему не стоит запрягать телегу впереди лошади


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Понедельник, 13 Май, 2019 21:11 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8089
Откуда: Троицк, Москва
Comdiv писал(а):
Спасибо, цитата пойдёт в педагогическое дело.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Вторник, 14 Май, 2019 00:45 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1352
Конечная остановка - классический Форт? :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Вторник, 14 Май, 2019 12:32 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 846
Откуда: Киев
Похоже, что нет
Александр Ильин писал(а):
число входных и выходных параметров не ограничено, но строго проверяется компилятором. Без этой последней проверки я вообще не понимаю, как можно написать что-то вменяемое - на том же Форте и миллионе его клонов.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Четверг, 16 Май, 2019 10:00 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Поэтому и хобби, оценка может поменяться.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Пятница, 17 Май, 2019 20:14 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 327
Comdiv писал(а):
Александр Ильин писал(а):
Программа на любом, даже самом чистом функциональном, языке программирования будет иметь некое "глобальное состояние" в процессе своего исполнения

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

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

В вики по ссылкам выше нюансы приведены размыто (в английской -- аналогично). Однако, утверждается, что "каноническим" (и первым) конкатенативным языком считается Joy (повлиял и на Factor). Его автор определил некую теорию по предметке, вот в его материалах более-менее разжёваны теоретические заморочки:
http://www.kevinalbrecht.com/code/joy-mirror/forth-joy.html
http://www.kevinalbrecht.com/code/joy-mirror/faq.html

Встречается и некая производная теория конкатенативных комбинаторов:
http://tunes.org/~iepos/joy.html

Нашлась неплохая статейка по тематике, и выступление на конференции того же автора:
http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html
https://youtu.be/_IgqJr8jG8M

Автор по последним ссылкам выше есть разработчик конкатенативного языка Kitten -- концептуально язык любопытный. Если Factor есть "постфиксный Lisp", то Kitten скорее "постфиксный ML", со статической типизацией, с возможностью использовать переменные, с инфиксными операторами (алгебраические) и "нормальными" условными конструкциями:
http://kittenlang.org/intro/
Код:
define reverse<T>
(List<T> -> List<T>):
  -> xs;
  match (xs head_tail)
  case some:
    unpair -> h, t;
    t reverse h append
  case none:
    []


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 19 Май, 2019 06:24 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Композиция определяется не языком, а семантикой.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 19 Май, 2019 09:26 
Аватара пользователя

Зарегистрирован: Пятница, 11 Май, 2007 21:57
Сообщения: 1167
Откуда: Украина, Киев
https://m.habr.com/ru/company/provectus/blog/452246/
Цитата:
Мир, в котором все будут программировать на Haskell — это вряд ли очень хороший мир. И если они не боятся идей ФП — это уже хорошо.

— А почему это будет плохой мир?

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


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Конкатенативный язык Factor
СообщениеДобавлено: Воскресенье, 19 Май, 2019 12:26 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1352
Ярослав Романченко писал(а):
https://m.habr.com/ru/company/provectus/blog/452246/
Цитата:
Мир, в котором все будут программировать на Haskell — это вряд ли очень хороший мир. И если они не боятся идей ФП — это уже хорошо.
— А почему это будет плохой мир?
— Потому что Haskell требует работы на очень высоком абстрактном уровне. И уровень человечества не позволяет, на мой взгляд, получить столько программистов, чтобы все задачи решать на Haskell. Чем меньше требуется уровень программиста, тем лучше, тем больше задач мы можем решить. Поэтому простые языки лучше, чем сложные.

Ну - прямо, как в том анекдоте:
"... вот так мы до серых мышей и доделаемся..."


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 21 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB