Pull to refresh

Comments 49

$error := {{ # начало блока try
	call_or_exception1(); 
	call_or_exception2(); 
}}; # конец блока try
# Аналоги блоков catch
($error ~ :type1)->{ код обработки ошибки 1}
($error ~ :type2)->{ код обработки ошибки 2};

Кажется, вы изобрели pattern matching но не до конца:

match VALUE {
  PATTERN => EXPRESSION,
  PATTERN => EXPRESSION,
  PATTERN => EXPRESSION,
}

let x = 1;

match x {
  1 => println!("one"),
  2 => println!("two"),
  3 => println!("three"),
  _ => println!("anything"),
}

Не, это аналог блока if ... else if, так как оператор ~, это оператор сравнение типов, а сама конструкция является полным аналогом:

if (<condition>) {
    EXPRESSION;
} else if (<condition>) {
    EXPRESSION;
}

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

($error ~ :type1)->{ код обработки ошибки 1}
($error ~ :type2)->{ код обработки ошибки 2};

Но у вас один и тот же предикат ($error) сравнивается с разными образцами.

Классический paattern matching. Да и синтаксис получился очень похожим, разве что более перегруженным.

С этой точки зрения да, похоже.

Но что делать, если потребуется дополнить проверку типа переменной каким либо дополнительным условием? Тогда нужно будет либо расширять лексические конструкции pattern matching (через какие нибудь | ), либо возвращаться на классический if ... else if, а вопросы оптимизации такой операции отдать на откуп компилятору.

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

Так и не надо изобретать, надо аккуратно взять то, что придумали в хаскеле)

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

Такой синтаксис не подходит из-за использования зарезервированных ключевых слов. Да и вряд ли приведенный вами пример относится к легким в понимании при беглом просмотре.

Да и вряд ли приведенный вами пример относится к легким в понимании при беглом просмотре.

Это индустриальный стандарт много лет.

Так и Python и C/C++ тоже много лет индустриальные стандарты. Тем не менее, некоторые места будут довольно сложными для понимания "с ходу". А про новые дополнения в синтаксис вообще лучше не говорить.

Ну окей, ваш язык, ваше право.

Только вот наколенный синтаксис скорее всего хуже общепринятого. Раст не похож на конформистский язык, но тем не менее, перенял синтаксис pattern matching из хаскеля почти 1-в-1. Думаю, уж они то понимают, что делают.

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

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

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

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

( ) Цикл

{ } Ветвление

[ ] Блок, список, стек

. Внутрь, к полю, к методу

! Наружу, выход из цикла

------- например: -------

Неделя (1..7) +1. или:

Неделя (1..7*) +1. или:

Неделя (1..7*Неделя) +1

{ День = 1..5} print [работаем]

{ День = 6 | 7 } print [выходной]

! +1* = 52

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

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

День := iter(1..5); # Итератор диапазона
(i := next(День)) <--> { # Цикл "while"
  print(i);
}

конфликтовать с остальным синтаксисом языка (например, использование квадратных скобок

Семантически -- массив, кортеж, мап, лист, json... — это одно и тоже. Поэтому квадратные скобки (как семантический маркер) могут помочь программисту понять на мета уровне. А это важно.

Синтаксическое противоречие (перегрузка) снимается парс-анализом. Например, звёздочка в скобках:

( )... ( *)... (..*)

{ }... { *}... {..*}

[ ]... [ *]... [..*]... [..*имя]

даёт "Оскар", ступеньку, расширяемость списка. Это может пригодиться для ИИ и его способности "расширять сознание", моделировать зеркальные нейроны, рефлексию и тп.

Допустим, венецианское зеркало даёт 40 отражений. Ставят свечу между двумя зеркалами и видят 40 отражений свечи. То есть, это механическая модель семантики рефлексии. Программно её можно отобразить:

а[..*а]

С какой целью вы хотите убрать ключевые слова? Я полагаю, чтобы увеличить абстракцию — семанто-ёмкость кода, смысловую фрактальность:

а[...] — это и именованный блок кода, и крейт, и трейт, и массив, и поля объекта, и строка/столбец таблицы, и html (div/span)... и ещё стек/куча всего-чего.

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

Идеализированная цель отказа от использования ключевых слов в синтаксисе, приблизить чтение текста программы к чтению обычного текста за счет использования знаков препинания при описании логики работы программы.

Конечно запятая человек может вычленять ключевые управляющие слова языка и слеш или учитывать форматирование запятая чтобы на их основе понимать синтаксические конструкции программы запятая хотя при обычном чтении мы привыкли опирается на семантику знаков препинания точка Мы конечно можем писать обычным текстом знаки препинания точка Но согласитесь запятая что такой текст открытая скобка именно этот текст закрытая скобка будет очень не удобно читать точка

Меньше ключевых слов должно же быть плюсом.

P.s. поддерживаю @Gordon01 что pattern matching вроде как известная языковая конструкция.

А я с ним не спорю про известность.

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

А как оформить само сравнение, if ... else if, switch ... case или pattern matching, это уже дело десятое.

Кстати, если говорить насчет pattern matching, то это будет хорошим дополнением к условному оператору. А его синтаксис можно нормально вписать в общую идеологию, например, вот так:

val => {
  match1 -> call1(),
  match2 -> {call2_1(); call2_2(); call2_3();},
  match3, match4, match5 -> call_multy(),
  _ -> call_any(),
};

Так что теперь @Gordon01от отцовства не отвертится и может считаться идейным вдохновителем добавления pattern matching в синтаксис NewLang!

Основной синтаксис NewLang — простой и логичный за счет того, что он построен исключительно на грамматических правилах и не использует каких либо зарезервированных ключевых слов, а все буквенно-символьные последовательности рассматриваются как идентификаторы в которых можно использовать любые не-ASCII символы.

Имхо, это не плюс, а большой минус, читать этот рассыпанный мешок символов пунктуации не удобно, это похоже на С++, где с этим огромные проблемы. Хотя, даже, скорее на Perl, который известен тем, что он write-only. Никто никогда не будет даже пытаться осознать, что означает последовательность

a :== { "^ ->>> print « $#% STR %#& » ° degree™convert <<<- ^" }

printf(str) := { %{ std::cout « $str; %} };

Написав это я имел в виду:

printf = (str) std::cout(str);

Я даже « с клавиатуры ввести не могу. Что вообще происходит?

iostream — одна из худших вещей в С++, зачем вы пытаетесь ее перенести?

Для создания объектов и присвоения им новых значений в NewLang используется сразу три разных оператора.

И все они — символ пунктуации. Зачем? Вы хотите переизобрести Brainfuck?

Так, символ «$» в начале имени обозначает локальную переменную, время жизни которой ограничено текущей областью видимости и при её завершении локальная переменная уничтожается. Символ «@» обозначает глобальную переменную, а сам объект сохраняет свое состояние даже после выхода из текущей области видимости.

Зачем? В 99,9% я буду использовать локальные переменные. Зачем вы приносите самое плохое из PHP/Perl?

iostream — одна из худших вещей в С++, зачем вы пытаетесь ее перенести?

Я ничего не переношу. Наоборот, вы процитировали пример кода на С++, который можно вставить между %{ %}, но нужно ли это делать, решать вам. А это просто демонстрация того, что у разработчика остается возможность использования обычного С/С++ в одном и том же контексте и не более того.

Что касается модификаторов имени, вы можете их использовать, но это делать не обязательно. Спасибо, дополню статью, чтобы насчет их было понятнее.

UFO just landed and posted this here

NewLang

Это название сразу же вызвало ассоциацию с Новоязом (NewSpeak) из романа Джорджа Оруэлла "1984".

Да, интересная ассоциация :-)

Вот вам и идея для промоушена в русскоязычном сегменте :)

Я человек простой: вижу новый язык -- ставлю минус. =)

А я наоборот стараюсь найти рациональное зерно, да и плюса не жалко.

UFO just landed and posted this here

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

Очередной алгол с нескучным синтаксисом — да, ненужен.

Простая интеграция с уже существующими программными библиотеками (в том числе импорт нативных переменных и функций из С/С++).

Вот это самое важное. Можно ли подробнее об интеграции с библиотеками и написании библиотек? Правильно ли я понял, что можно использовать только в C-стиле - переменные и функции, но не классы C++? Так же и по поводу библиотек NewLang и их вызова из других языков - есть такая функциональность?

Тут все и просто и сложно одновременно.

Импорт нативных С функций сделан из коробки, а их вызов происходит с помощью библиотеки libffi с автоматической проверкой и преобразованием типов данных.

Пример использования обычных файловых функции можно посмотреть в тесте TEST(Eval, Types) в файле: https://github.com/rsashka/newlang/blob/master/core/test/eval_test.cpp

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

Сложно, потому что сейчас импортируются объявления, помеченные только extern "C". Я пробовал использовать clang для создания декорированного имён функций или класса. В принципе это возможно, хотя сейчас это задача не первоочередной важности, но в будущем я планирую это сделать. Еще есть проблемы с перехватом ошибок (сишные функции не кидают иссключений, а ловить SIGTERM или SIGABRT та еще проблема).

Сейчас модуль NewLang, это обычная динамическая библиотека (файл .so) скомпилированная из С/С++ файла (когда работал компилятор). В нем не используется ни сборщик мустора, ни глобальный объект синхронизации. Поэтому нет никаких препятствий для использования модулей NewLang из других языков программирования.

Сишные функции не кидают исключений, а сигналы это зачастую уже не исключения, а ошибки. Для исключений делается обёртка в вашем языке, проверяющая значение кода возврата функции и/или errno, и выкидывающая исключение на основе этих значений.

Это комбайн для ML, бэка или для фронта или для всего сразу? Как обстоит дело с поддержкой DSL или с внедрением генерируемого текста (например HTML) в строку?

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

Поддержка DSL закладывается изначально идеологически, хотя сейчас это никак и не реализовано на практике.

Синтаксис для встраивание форматированного текста сделан как в Python с использованием тройных кавычек. Этот момент уже реализован в лексере и парсере, но я его не проверял и не тестировал.

По поводу названия есть такой комментарий — лет через 5-10, NewLang будет еще «New» или уже нет?

Знаете, если через 5-10 лет ответ на этот вопрос будет иметь смысл (язык будет доведен до рабочего состояния и реально использоваться), то ответ на него будет не важен, т.к. термин NewLang будет нарицательным, а не переводится по частям.

И это будет уже из области "Монти Пайтон", С, D, С#, за каждым названием есть какая то история.

Выглядит интересно. Но планируемая кодогенерация в C++ звучит немного пугающе. И вставки кода C/C++ явно намекают, что будет "лобовая" кодогенерация.

На самом деле все не так уж и страшно. Да, сейчас трансплайтер генерирует код "в лоб" без какого либо анализа, но принципиальная привязка к С/С++ как таковая отсутствует.

Я начинал эксперименты на Python, и вставки кода там работали точно по такой же схеме. Правда, когда начал делать компилятор, пришлось перейти на C/C++, тем более он для меня привычнее.

Но конечная цель, JIT кодогенерация под LLVM, а это гораздо проще сделать с С/С++, чем с любого другого языка.

На самом деле, вам бы обратить внимание в этом плане на языки, где такие фокусы разрешены. Например, сразу вспоминаются ассемблерные вставки в Си/Си++/Паскале, а следом за ними более сложные примеры типа Bison и JSP. Первая же проблема, которая появляется -- это использование имён в кодовой вставке. Вторая -- это порядок исполнения (особенно, когда внешний язык замахивается на декларативность). И наконец -- это проблемы оптимизации. Намного лучше связывать языки через линкер, для чего продумывать ABI, ну или хотя бы через компилятор нижнего языка, без возможности вставки кода на нижнем языке в ваш, используя API

Спасибо за комментарий!

Я уже с самого начала смотрел (как вы и советовали) на синтаксис того же bison. Более того, некоторые вещи из него я и позаимствовал (синтаксис вставки кода на языке реализации и обращение к аргументам как раз из него).

Описанные проблемы действительно существуют, но использование имен функций пересекается только с PHP, но вряд ли у кого нибудь появится желание на нем переписать NewLang :-). А в остальных мейнстримных языка имена переменных и функций не используют префиксы. А проблемы порядка исполнения и оптимизации я надеюсь уйдут после реализации компилятора.

Я не очень понял вашу мысль про PHP. Я намерено не написал про него в своём комментарии, потому что про PHP нельзя сказать, что в нём используются вставки на другом языке. Если вы хорошо знакомы с PHP, вы должны знать, что между ?> и <?php можно заключить текст таким образом, чтобы он подчинялся логике, написанной на языке (заключить в условие или в цикл). То есть это не код на PHP встраивается в файл, а текст встраивается в код на PHP, что сразу не очевидно. Поэтому там вообще всё сложно.

Я, говоря про имена, имел ввиду проблему макросов. Если вы знакомы с препроцессором C/C++, то должны знать, что при использовании имён в макросах, они подставляются в код программы как есть и нет никакой возможности создать уникальное для конкретной подстановки имя. В случае вашего языка, если я всё правильно понимаю, это может привести к намеренному или случайному нарушению логики сгенерированного кода за счёт использования внутренних имён, которые вы наверняка генерируете, в коде на C++. И напротив, если вам потребуется для каких-либо целей изменить имена переменных из вашего языка в сгенерированном коде, то вам придётся также предоставлять удобный механизм обращения к ним в коде на C++. Учитывая, что у вас используется динамическая типизация, у вас должен быть общий тип для всех значений, а значит, работать с такими значениями как с простыми значениями в кодовой вставке уже не получится. Надеюсь, я смог донести свою мысль

Про PHP я написал не из-за способа вставки кода, а из-за того, что у PHP, в отличие от Python, Java, C/C++ и пр. используются префикс у имен переменных, так же как в NewLang. И из-за этого в программной вставке нельзя отличить переменную NewLang от переменной PHP.

Все правильно, речь идет фактически о макросах и программные вставки обрабатываются точно так же. Ищется вхождение переменой (по её префиксу $ или @) и оно заменяется на имя внутренней сгенерированной переменной. Оно действительно может пересечься с используемым, но это не проблема, т.к. правила создания имен внутренних переменной на языке реализации определяются заранее. И при желании можно обратится к ним на прямую даже без использования раскрытия программных вставок.

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

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

Тогда в коде вставляется вызов функции с динамическим приведением типа к нужному. Внутри него происходят проверки возможности каста к требуемому типу и после этого возвращается значение в требуемом машинном формате.

Новый язык программирования

Вот прямо просится

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

Программные вставки расширенного синтаксиса на языке реализации ... любой код на C/C++

А после раскрутки компилятора необходимость в %{ ...%} отпадёт или там всё равно будет С++?
Или раскрутка не планируется?

В эпоху машинного обучения тензоры являются основными элементами вычислений

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

($ для локальных объектов и @ для глобальных)

Продолжая предыдущую мысль: глобальные объекты в многопотоке - боль.

А после раскрутки компилятора необходимость в %{ ...%} отпадёт или там всё равно будет С++? Или раскрутка не планируется?

Тут ключевое "язык реализации". Вставки я планирую оставить, т.к. это часть бесшовной интеграции между двумя синтаксисами. Но язык реализации может быть любой. Просто сейчас это С++, но может быть Python, Rust и т.д. Зависит от того, для какого языка сделан трансплайтер.

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

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

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

Sign up to leave a comment.