LINUX.ORG.RU

\[палёный мёд\] фантазии на тему своего ЯП

 , , ,


0

4

Привет, котаны!

Я решился на отчаянный шаг — поэкспериментировать с компиляторами. После долгого сидения я понял что питон это не то — надо шагнуть дальше. Ну, хотя бы в с т.з. функционального программирования. Сразу скажу что концепции я пока не вижу и ответов на фундаментальные вопросы типа степень ленивости языка, всякие там монады, в каком виде делать ООП (и делать ли?) у меня нет. Но всё же забавно поиграться просто с синтаксисом.

Основные приоритеты: компактность, наглядность, удобное представление рутинных действий. Цели: высокоуровневое системное программирование. Т.е. целей писать на нём ядро нет, вопросы скорости пока не интересует. Скажем, хотелось бы ЯП чтобы можно было легко писать как скрипты аля-шелл, так и полноценные программы. Но внутренние детали я бы хотел обсудить позже, и так вопросов куча. Вот что родилось в моём больном воображении:

/* DATA TYPES */
//ints and floats, types are infered from the value
i = 1; f = 1.0
// list
l = [1,2,3]
//tuple (arguments of functions are passed in tuples)
t = 1, 2, 3
//tuple with named fields
tuple X: a, b, c
x = X a=1, b=2, c=3
// the same but with optional parens
x = X(a=1, b=2, c=3)
// access tuple attrs
print x.a, x.b, x.c
//hashes
{}  // empty hash
h = {b=>2,a=>1}
print h.keys // -> "pb, a]" because hashes preserve insert order

//regular expressions
pattern = /[A-z][a-z]{1-2}/


/* BASICS */
// define variable
x = 1

// define function "z" of two args
z x:int, y:int = 2*x + y

// function invocation
z 1, 2
// or
z x=1, y=2

// composition, equivalent of print(z(1,2))
print z 1, 2

// conditions:
if a > 2:
  pass
//if-else in one line
if x == 2: {x = 3} else: {x = 4}
//regexp
if x ~= //


switch x:
  x == 1: pass
  x < 10: print("x is really less than 10")
          continue  # go down
  x < 5 : print("x ")
  _     : print("what a strange X")


/* SUGAR */

# shell invocation
x = `ps ax | wc -l`


# equivalent of vm = VM(); ...; vm.stop()
vm1 = VM(), vm2 = VM():
  on cleanup:
    vm1.stop and vm2.stop():
  ...


/* HIGHER ORDER FUNCTIONS */
# a(b(c))
c | b | a
a . b . c

/* GROUPING */
// block may appear at any place where expression is acceptable.
// the return value is the last statement
// statements are separated by semicolon.
x = true
if x: {print "it turned out that x is true"; x=false}
else: {print "x is false, sad but true"; }


/* HELLO, WORLD */
main argv =
  print "hello, hell"
  print "my args:", argv

/* STRING SUBSTITUTION */
x = 666
print "x is equal to ${x+1}" // equivalent of { tmp = x+1; printf("x is equal to %d\n", tmp) }

/* EXCEPTIONS */
// catch exception and get its value in _err
fd = open "filename" || die "exception ${_err}"

try:
  fd = open "filename"
except NotFound:

fd = try {open "filename"} except NotFound: -1


/* LANGUAGE MODES */
//shell invocation in backticks
files = `ls -la /tmp`
`for f in ${files}; do scp $f remote:/tmp; done` \
  || die "scp failed with ${_err}"


/* COMMENTS */
// this is a comment
# and this is a comment
/* and this as well */
; have fun with many comment styles


/* SMALL THINGS */
for elem in some_list:
  ...
print elem  //will raise error because loop variables are not seen outside the loop by default

// for this reason file will be automaticaly closed once the control reach the end of the loop
for l in os.open("some_file"):
  ...

PS кодовое название — velosipedix. PPS case ymn, archimag, baverman, tailgunner, qnikst, mv и всех других кого забыл :)

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

★★★★★

Последнее исправление: CYB3R (всего исправлений: 2)

После долгого сидения я понял что питон это не то

Наконец-то хоть кто-то это понял!

CYB3R ★★★★★
()

Нечитабельно и вообще не понятно, зачем это нужно.

Система типов какая? Или динамика?

geekless ★★
()

Это такой руби, только хуже.

Особенно доставили нестыковки в примере определения функции и реализации мейн (там тип аргв не указан), и идея задавать имена переменных ДО вызова функции (f x = a, y = b - это же как-то совсем неестественно).

cdshines ★★★★★
()
/* COMMENTS */
// this is a comment
# and this is a comment
/* and this as well */
; have fun with many comment styles

нужно построить зиккурат!

nanoolinux ★★★★
()

а еще немного паттерн-матчинга и атомов, блоков кода, анонимных функций?

swwwfactory ★★
()

И если уж тут недавно жаловались на тяжелую грамматику руби, то я представляю себе грамматику этого монстра.

Кстати, почему никто сейчас не велосипедит гомоиконные езыки?

cdshines ★★★★★
()
// composition, equivalent of print(z(1,2))
print z 1, 2

А если кто-то напишет print(z,1,2), где print - ФВП, которая принимает первым аргументом функцию, то будет путаница.

cdshines ★★★★★
()
Ответ на: комментарий от geekless

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

cdshines ★★★★★
()

После долгого сидения я понял что питон это не то

В каких местах твой velosipedix лучше?

eugeno ★★★★★
()

Чем тебе питон не понравился, если ты все-равно используешь отступы как операторные блоки (ну не блоки, я забыл правильное название)?

fd = open «filename» || die «exception ${_err}»

это вообще луа напоминает.

rikardoac
()
Последнее исправление: rikardoac (всего исправлений: 2)

*тред не читал...
а чем руби, ну или питон, не устраивают?

etwrq ★★★★★
()

because hashes preserve insert order

Двойной капучино этому сеньору!

arturpub ★★
()

О, новый лиспер подрастает.

anonymous
()

//if-else in one line
if x == 2: {x = 3} else: {x = 4}

Можно и без фигурок, если парсер поверх сканнера.

А самое главное — ни слова не сказал про скопинги, управление памятью, метапрограммирование и модульность.

arturpub ★★
()

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

whatever  / 25 ; # / ; die "this dies!";

Schwartz's Snippet can parse two different ways: if whatever is nullary (that is, takes no arguments), the first statement is a division in void context, and the rest of the line is a comment. If whatever takes an argument, Schwartz's Snippet parses as a call to the whatever function with the result of a match operator, then a call to the die() function.

Подробное описание проблемы: http://www.perlmonks.org/?node_id=663393

По-русски, кратко:

1. Если функция не принимает никакие аргументы, то получаем комментарий в конце:

whatever() / 25; # / ; die "this dies!";

2. Если принимает, то получим такое:

whatever(/ 25 ; # /); die "this dies!";

gh0stwizard ★★★★★
()

И таки не tuples, а structs же. Tuples удобны сами по себе.

arturpub ★★
()
Ответ на: комментарий от rikardoac

Code = Data Code and data are the same; the only difference is in how they are interpreted. Both use the same source format. They are indistinguishable in memory. Code can be interpreted as data. Data can be interpreted as code. Both can be saved and loaded from files.

cdshines ★★★★★
()

Это ты типа не осилил скомпилять питонопограмму?

derlafff ★★★★★
()

Оптимально сделать что то на смеси питона и плюсов. Питон оченно расширяемая байда;-)

Вообще, создать идеальный ЯП невозможно. Поэтому лучше сделать тулзу, позволяющую мешать разные существующие ЯП.

AIv ★★★★★
()

блин, и после этого какие-то люди говорят «У Ruby плохой синтаксис».

Alve ★★★★★
()
Ответ на: комментарий от cdshines

Мне лично кажется, что вполне является, но я не особо знаю ребол, так, пробежался по синтаксису.

rikardoac
()
Ответ на: Tcl от anonymous

Плюсую.

olibjerd ★★★★★
()

тебе нужен руби :)

kelyar ★★★★★
()

because hashes preserve insert order

Бгг. Постоянный оверхед? No way.

«=>»

ага, сделаем все как не в питоне. Кстати, а где прекрасные множества?

Ну и далее просто неудобоваримое мессиво.

Черновик черновика, не более.

baverman ★★★
()

Я тут нашел описание грамматики выражений какого-то своего черновика ЯП, который набросал лет 5 назад. В общем, я просто оставлю это здесь. (Я не знаю, чем я упарывался.)

Приоритет и ассоциативность операций.

left             `
left             or
left             and
right            =, bin_op=
left             ? :?
left             ||
left             &&
left             |
left             ~
left             &
non-associative  ==, !=
non-associative  <, <=, >, >=
non-associative  in
left             shl, shr, rol, ror
left             +, -, 
left             *, /, -/
left             \r
right            \b, \rd
left             :...
left             :., операции объединения
left             ::, :*, операции поиска и выборки
left             as
right            !, ~(унарная), +(унарная), -(унарная), new, %..., <>...
right            ++ --
left             ^
left             ., ->, [], (), of


Простые операции.



Арифметические:
+(унарная) пустая операция
-(унарная) смена знака
+ сложение 
- вычитание
* умножение
/ деление
-/ взятие остатка
Для взятия остатка выбрана такая операция, поскольку -/ можно воспринимать
как сокращение a - a / b. По аналогии с конструкциями вида a += b логичнее
было бы /-, но это конфликтует с унарным минусом: a/-b.

Побитовые:
shr сдвиг вправо
shl сдвиг влево
ror вращение вправо
rol вращение влево
~   побитовое исключающее или
|   обитовое или
&   побитовое и
~(унарная) побитовое отрицание

Равенства:
== равно
!= не равно

Сравнения:
<  меньше
<= меньше или равно
>  больше
>= больше или равно

Логические:
&& логическое и
|| логическое или
!(унарная) логическое отрицание
and, or, not - аналогично, но с иным приоритетом.


Выборки:
:: выборка элемента из контейнера по ключу
:* выборка элементов из контейнера по ключам

vec::i // i-й элемент в vec, аналогично vec[i]
vec:*[1...10, 4] // выбрать с 1-го по 10-й, а затем 4-й (повторно)

Поиска и выборки:
Данные операции конструируются по следующему шаблону:
":" "!"? (">" | "<" | "*") ("<" | "<=" | ">" | ">=" | "!=" | "==" | "/")
Если имеется "!", результатом служит ключ(ключи) найденного
элемента(элементов), иначе - значение элемента.
Если далее идёт ">", поиск осуществляется от начала к концу,
если "<" - от конца к началу, если "*" - поиск осуществляется
по всему контейнеру и тип результата - контейнер с выбранными
элементами. Далее указывается либо:
1) либо одна из операций "<", "<=", ">", ">=", "!=", "==",
в этом случае осуществляется поиск элемента, для которого
данная операция истинна (при сравнении со вторым операндом),
2) либо символ "/", в этом случае второй операнд - функция-фильтр.
Примеры:
vec:!<==' ' // возвращает ключ элемента со значением ' ', поиск с конца
vec:>/filter // возвращает значение элемента, для которого filter вернул true, поиск с начала

vec:*/filter // выбрать все элементы, для которых функция filter вернула true


in имеется ли в контейнере (второй операнд) элемент, равный первому операнду

' ' in vec


Конкатенации:
:. конкатенация

vec = ['a', 'b', ' ', '0'];
vec:.['q', 'w'] // ['a', 'b', ' ', '0', 'q', 'w']


Объединения:
Данные операции конструируются по следующему шаблону:
":" операция_для_уникальных_ключей операция_для_неуникальных_ключей.
Два контейнера объединяются по ключам.
Ключи, которые имеются только в одном контейнере:
*  включать элементы из обоих контейнеров
1  включать элементы из левого контейнера
2  включать элементы из правого контейнера
0  не включать эти элементы
Ключи, которые имеются в обоих контейнерах:
1  включать значения элементов из левого контейнера
2  включать значения элементов из правого контейнера
== включить только совпадающие в обоих контейнерах значения
!= включить только не совпадающие в обоих контейнерах значения
>  включать большее значение
<  включать меньшее значение
0  не включать эти элементы
Примечание. Сочетания :11, :22, :00 разрешены. Результат, соотвественно,
левый контейнер, правый контейнер и пустой контейнер.

Примеры:
v1:0==v2 // найти пары ключ-значение, общие для обоих контейнеров
v1:20 v2 // найти пары элементы с уникальным ключём в правом контейнере


Приведения типа:
as - привести к указанному типу
a as integer // привести a к типу integer


Присваивания:
= присваивание



Выражения-операции.

Инверсия.
bin_op : "\" bin_op;
Значение: a "\" bin_op b === b bin_op a

Сложное присваивание.
bin_op : bin_op "=";
Значение: a bin_op "=" b === a "=" a bin_op b

Выбор.
bin_op : "??" bin_op;
Значение: a "??" bin_op b === a bin_op b "?" a ":" b

Примеры:
a ??> b // большее из a и b



Свёртка. (Reduce)
un_op : "\r" bin_op;
Значение: "\r" bin_op a === {if %len a == 0, raise Exc; auto i = %iterator a; __result = i++^; foreach auto v in i, __result bin_op= v;}

Свёртка со значением по умолчанию. (Reduce with Default)
bin_op : "\rd" bin_op;
Значение: b "\rd" bin_op a === {__result = b; auto i = %iterator a; foreach auto v in i, __result bin_op= v;}

Примеры:
\r+[1, 2, 3] // 1 + 2 + 3
5 \rd+[1, 2, 3] // 5 + 1 + 2 + 3
a\rd??>=vec; // Среди значения a и всех значений
контейнера vec выбрать максимальное при присвоить a.

Разветвление. (Branch)
un_op : "\b" un_op*(1) "{" bin_op "}" un_op*(2) ;
Значение: "\b" un_op*(1) "{" bin_op "}" un_op*(2) a === (un_op*(1) a) bin_op (un_op*(2) a)

Примеры:
\b\r+{/}%len v // то же самое, что (\r+ v) / (%len v), т.е. вычисление среднего арифметического элементов v

Понижение до унарной операции.
(Объединение последовательности бинарных операций в унарную.)
un_op : "%" "{" bin_op expression { "," bin_op expression}  "}" ;
Значение: "%" "{" bin_op expression { "," bin_op expression}  "}" a === алгоритм:
1) __result(0) = a;
2) для каждого i-го фрагмента вида bin_op expression,
__result(i) = __result(i-1) bin_op(i) expression(i);
Следует обратить внимание, что переменные __result(0),
__result(1), __result(2) и т.п. - это разные переменные, могущие иметь разные типы.


\b \r+%{:/filter1} {/} \r+%{:/filter2} v
// Выбирает из v элементы по фильтру filter1, ищет их сумму;
// выбирает из v элементы по фильтру filter2, ищет их сумму;
// находит частное от сумм.

Векторизация бинарной операции.
bin_op: "bin_op" "<" a1 a2 ">"
Значение: бинарная операция применяется к парам значений
(с совпадающими ключами) из двух контейнеров. Параметры a1 и a1
указывают, как поступать с элементами (соотвественно, в левом и
правом контейнере), которые не имеют пары:
"e" - иницировать исключение при встрече такого элемента
"i" - игнорировать такие элементы и не включать в контейнер-результат
"r" помещать такие элементы в контейнер результат без выполнения над ним вычислений
"{" expression "}" использовать в качестве пары
    значение expression (значение вычисляет один раз в начале
    выполнения векторизованной операции)
"!{" expression "}" использовать в качестве пары
    значение expression (значение вычисляет для каждой пары
    заново)
"l" использовать в качестве пары значение, свойства last
    другого контейнера
"f" использовать в качестве пары значение, свойства first
    другого контейнера
Если a2 отсуствует, подразумевается "i".
Если и a1, и a2 отсутствуют, подразумевается "i" "i".

Частичная (левая) векторизация бинарной операции.
bin_op: "!" "bin_op" 
Значение: a "!" "bin_op" b.
Аналогично векторизации, но в качестве второго аргумента
выступают не значения из b, а само значение b.

Частичная (правая) векторизация бинарной операции.
bin_op: "bin_op" "*"
Значение: a "bin_op" "*" b.
Аналогично векторизации, но в качестве первого аргумента
выступают не значения из a, а само значение a.

Векторизация унарной префиксной операции.
un_op: "un_op" "*"
Векторизация унарной постфиксной операции.
un_op: "!" "un_op" 

Примеры:

%{/2}* (a +<> b) // Среднее арифметическое для каждой пары элементов
(a +<> b) !/ 2 // аналогично предыдущему

(vec:*<16)!++ //Инкрементировать все элементы, меньшие 16.


stream :write* v // Записать в stream элементы v.
geekless ★★
()
Последнее исправление: geekless (всего исправлений: 1)

слабовато... я бы сказал... вычурно и топорно...

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

mm3 ★★★
()
Ответ на: комментарий от geekless

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

mm3 ★★★
()
Ответ на: комментарий от mm3

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

Есть такой язык, его интел написала, называется Core i7. А «описания популярных синтаксисов» тоже есть. Называются gcc, python, ruby, perl...

geekless ★★
()
Ответ на: комментарий от baverman

«=>»

Откуда знать, может это у него алиас на запятую с баревордингом, как в перлах?

arturpub ★★
()
Ответ на: комментарий от cdshines

А если кто-то напишет print(z,1,2), где print - ФВП, которая принимает первым аргументом функцию, то будет путаница.

нет, почему же, тогда бы было print z 1,2

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

так у тебя уже есть print z 1, 2 == print(z(1,2)), то есть вызывается z(1,2), а печатается ее результат. а я говорю про передачу такого з в принт, например print (lambda (a,b) -> a + b) 1, 2, и там уже эта лямбда применяется к (1,2). Ты же понимаешь разницу?

cdshines ★★★★★
()

Смотрите, дети, что получается, когда о ЯП пытаются фантазировать люди без образования.

anonymous
()

После долгого сидения я понял что питон это не то — надо шагнуть дальше.

Скажи нормально: не осилил, надоело учить.

vurdalak ★★★★★
()

Сколько ж питонутых на всю голову в треде.

anonymous
()
Ответ на: комментарий от cdshines

Кстати, почему никто сейчас не велосипедит гомоиконные езыки?

Есть один, который закрывает многие «дырки», но из-за своей непохожести на «лисповый мейнстрим» (CL и схема) даётся с огромным трудом - picolisp.

Если создаваемый язык «для всего», то очень быстро приходишь к тому, что сам язык (компилятор / интерпретатор) хочется писать именно на этом языке, за исключением минимального ядра. Далее первое - это работа со списками, т.е. очень нужен gc или что-то упрощающее работу с памятью, ибо колбасить «списки из списков» приходится постоянно, а иметься с памятью - «не царское дело». Второе - если не идти через 8 стадий (может это и правильно, но получается оооочень муторно), то нужны макросы или что-то подобное, следовательно, либо интерпретатор, либо jit. Интерпретаторов и так как собак - не интересно. Остаётся jit. И так, нам нужен gc и jit. Лёгкий путь - jvm (или mono для извращенцев). Тяжёлый - llvm как лучшая на сегодняшний момент связка «компилятор + jit», но gc прикручивать сторонний, да и нет сторонних по параметрам сравнимым с «промышленными» (jvm), или хотя-бы с тем-же sbcl.

И так, ты ещё ничего не написал, но уже понимаешь, что либо ты привязываешься к готовой платформе и становишься её заложником и заложником её возможностей, либо тебе надо расковырять до зубного нерва llvm и собрать команду для написания конкурентно-способного gc (во всех смыслах).

Это ещё не обсуждались возможности самого языка, системы типов и т.д.

yyk ★★★★★
()
Ответ на: комментарий от geekless

вообще интересно, хотя местами чересчур громоздко

а по какому образцу/идее/... сделаны векторные операции?

кстати, (a<b<c) это очевидно же (a<b)&&(b<c), так что ассоциативность должна быть

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от mm3

Racket, Katahdin, с некоторой натяжкой Rebol. Так же нечто подобное возможно в Coq и Shen.

anonymous
()

а цель сформулировать слабО?

например, «питон почти устраивает, но хочу для него другой синтаксис»

www_linux_org_ru ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.