ВВ>; на каждой строке плохо, но с ним можно бороться. Есть два варианта.
ВВ>1. (то, что реализовано) Точка с запятой является необязательной в том случае, если выражение является последним в блоке или же если оно следует сразу после выражением, которое заканчивается на }
ВВ>2. Убрать точку с запятой на фиг вообще. Ввести такой принцип — перед всеми "простыми" выражениями (т.е. теми, которые в обычных языках только и считаются за выражения) писать специальное ключевое слово. Например, do. ВВ>Говоря другими словами, у нас теперь все конструкции языка начинаются с ключевого слова. Вуаля, конфликтов нет. Ну делаем поблажку на то, что если у нас выражение одно-единственное в блоке, то do можно не писать:
Извини что встреваю в беседу
Можешь пояснить, чем точка с запятой в конце конце каждого выражения не устраивает?
Здравствуйте, night beast, Вы писали:
NB>Извини что встреваю в беседу NB>Можешь пояснить, чем точка с запятой в конце конце каждого выражения не устраивает?
Видать лаконично больно, хочется по больше символов писать. Я вот тоже хочу предложить в русском языке точку отменить, а вместо нее каждое предложение начинать с префикса НОВОЕ, это ж как бы читабельность текста повысило.
Здравствуйте, night beast, Вы писали:
NB>Извини что встреваю в беседу NB>Можешь пояснить, чем точка с запятой в конце конце каждого выражения не устраивает?
Ну речь в общем о том, что убрать из синтаксиса мусор — а во многих случаях и так видно, что у тебя разные выражения, зачем еще точки с запятой?
А вообще тут дополнительные сложности как бы создает тот факт, что разделения на expression и statement нет, поэтому такой код валиден:
var x = if (cond)
firstAction()
else
secondAction();
Вот скажи, ты бы хотел его записывать так:
var x = if (cond)
firstAction();
else
secondAction();;
Здравствуйте, Undying, Вы писали:
U>Видать лаконично больно, хочется по больше символов писать. Я вот тоже хочу предложить в русском языке точку отменить, а вместо нее каждое предложение начинать с префикса НОВОЕ, это ж как бы читабельность текста повысило.
Ага, только "символов" на самом деле будет гораздо меньше.
T>>>>Согласно каким правилам "var x= 2" и "var x = 2" равнозначны, а "arr[index]" и "arr [index]" — нет? ВВ>>>Ну я у тебя спрашиваю. Они равнозначны или нет? Или же "var x= 2" и "var x = 2" — это разный код? И какой тогда правильный? В первом случае будет ошибка? Или что будет? T>>Опять же, согласно каким правилам?
ВВ>Ты предложил этот вариант и спрашиваешь меня о правилах? Нет уж, расскажи о правилах сам. Вариант был, напомню, использовать в качестве разделителя пробел. ВВ>Вот я и спрашиваю, как этот пробел будет работать в остальных случаях.
Хакей, у меня такой вариант: x= 2 это ошибка, вокруг операторов (кроме '.') должен быть пробел.
ВВ>>>И вот когда выполняется min, нам сделать некую проверку, определить, что print особого типа и начать выполнять совсем не тот код, который был сгенерирован компилятором. Ну т.е. это вообще практически нереальный сценарий. T>>Да, Min должен проверить типы аргументов и кинуть TypeError.
ВВ>Ты опять нить потерял. Речь была о том, чтобы суметь определить, что print — x это на самом деле не бинарная операция, а две операции: 1) вызов функции 3) negate x ВВ>TypeError и так будет. ВВ>А вот определить, что это две операции можно уже только при выполнении Min. Короче, это вообще какой-то бредовый вариант.
Да, точно, потерял.
Так вот, парсер запишет "print — x" как бинарный минус и будет ошибка, в то время как пользователь хотел "print -x". Ну да, обнаружится во время исполнения. Как и все остальные ошибки в динамическом языке.
ВВ>>>Вообще я сделал выводы из тех обсуждений "вездессущий null" отсутствует. Вместо него — void. А это подход, который проповедуется большинством функциональных языков, только там void часто называется unit. Блок else — обязательный. T>>Не понял какие выводы. null переименовал в void? ВВ>null это не void
Какие выводы?
T>>И "большинство ф-х языков" это сколько/какие?
ВВ>Все языки семейства ML тебя устроят? Scala? Haskell? Nemerle?
В хаскеле точно нет ни void, ни unit.
ВВ>>>То, что ты описываешь — это скорее этакая do-нотация для энергичного вычисления выражений с побочными эффектами. Она имеет смысл при ленивости всего остального и чистоте языка. У меня блок это просто блок, он не гарантирует последовательности. Внутри него могут быть и ленивые выражения. T>>У тебя { expr1; expr2; expr3 } не гарантирует последовательности? Последовательность и ленивость ортогональны, кстати.
ВВ>Не гарантирует последовательности *исполнения*. Да, такой не гарантирует. Это тебе не монада.
Круто.
(монада в общем смысле тоже не гарантирует кстати. Только IO)
T>>(питона там не было) T>>Покажи любую функцию размером больше 150 символов из своей стандартной библиотеки.
ВВ>А что ты конкретно хочешь увидеть? Стандартная библиотека еще не написана. Есть код для тестов.
Я хочу увидеть (и показать) как (в худшем случае) N-1 выражений в каждом блоке не используются.
T>>f _ = "Hello world" T>>print f T>>Ты можешь сказать, что в print передаётся функция f, ты можешь сказать, что в print передаётся результат вычисления функции f. Ты будешь прав в обоих случаях. T>>Потому что результат вычисления функции f это нулларная функция, возвращающая "Hello world". Маниакальное каррирование даже там, где не просят. Это затрудняет создание функций с произвольным количеством аргументов. Я думал над этим и не придумал хорошего решения.
ВВ>Ничего не понял. Как мне описать функцию, которая принимает один аргумент и совершает операцию над этим аргументом?
add_1 :: Number -> Number
x = x + 1
T>>Я не понял вопроса. Но вот этот тип T>>x :: String T>>описывает функцию с именем "x" с 0 аргументов, которая возвращает строку. T>>Функциональным, обычно, называют тип a → b. Даже если b при этом сам является c → d. Оператор → правоассоциативен, как минус.
ВВ>Опять ничего не понял. Функциональный тип у которого 0 аргументов?
Можно убрать слово "функциональный" чтобы выглядело более естественно. Смысл не изменится, потому что всё есть функция. Думаю, что именно в этом и кроется смысл выражения "функциональный язык".
T>>Если всё стало выражением, это значит только то, что ты теперь получил кучу гемора с определением какой же результат должен быть у всего. T>>Например, "for" ты потерял, потому что у него результата нет. Сказать на всё, что раньше было стейтментом, что у него результат — специальное значение void, это и есть создать именно лишнюю сущность, закрыть глаза на проблему выражений, создать костыль.
ВВ>Сохранение этого разделения представляет собой костыль куда больший. Оно в сущности означает, что для написания кода тебе по-прежнему придется использовать типичные конструкции императивного flow control — return и прочая. ВВ>К тому же я тут ровным счетом ничего не изобрел.
return сам по себе неплох. Просто нужно помнить, что он ещё и вызывает продолжение, т.е. по сути это name-bind + goto. Так вот, как минимум первая его половина — полезна очень.
Не изобрёл, да. Довольно сложно что-то изобрести вообще.
T>>- Эта идиотская идея, что типы документируют код. Это работает только в примитивных случаях, где и документировать нечего. T>>- Обязательная ленивость. Иногда всё-таки хочется взять на себя ответственность и указать порядок. T>>- Вся стандартная библиотека завязана на один конкретный тип последовательности: односвязанный список (который имеет конструктор ':'). Как следствие, для Array, Set, Map и пр. — свои, отдельные операции. Например, map/filter/fold работают *только с []*. T>>- Самая странная, убогая реализация туплов в мире. Это 64 строки типа http://google.com/codesearch/p?hl=en#5KTrgOW2hXs/pub/nslu2/sources/hugs98-Nov2003.tar.gz|cVG3t241wQU/hugs98-Nov2003/fptools/libraries/base/Data/Tuple.hs&q=%22%28,,%29%20a%20b%20c%22&l=71 T>>- main имеет "грязный" тип IO. То есть на хаскеле нельзя писать чистые программы, только чистые функции.
ВВ>Кстати, а на чем ты собираешься все это писать? И во что компилировать?
Был микропроект по написанию парсера. На хаскеле
Компилировать это отличный вопрос. На первом этапе, честно говоря, я собирался сделать интерпретатор, как более простой вариант.
Но мечта идиота — компилить в LLVM IR.
Здравствуйте, Воронков Василий, Вы писали:
NB>>Извини что встреваю в беседу NB>>Можешь пояснить, чем точка с запятой в конце конце каждого выражения не устраивает?
ВВ>Ну речь в общем о том, что убрать из синтаксиса мусор — а во многих случаях и так видно, что у тебя разные выражения, зачем еще точки с запятой?
if (cond) expr#1 expr#2
как должно выполняться?
ВВ>А вообще тут дополнительные сложности как бы создает тот факт, что разделения на expression и statement нет, поэтому такой код валиден:
не видя грамматику трудно что-то сказать.
ВВ>var x = if (cond)
ВВ> firstAction()
ВВ> else
ВВ> secondAction();
ВВ>Вот скажи, ты бы хотел его записывать так:
ВВ>var x = if (cond)
ВВ> firstAction();
ВВ> else
ВВ> secondAction();;
ВВ>Можно представить себе грамматику где подобная конструкция неконфликтна.
да я не спорю что не конфликтна
что должно быть про cond == false? выполняться только #2 или ничего
NB>>а почему бы не требовать ";" только в блоке кода?
ВВ>Не понял.
if (cond) { 1; 2; } -- хорошо
if (cond) { 1; 2 } -- плохо
Здравствуйте, Temoto, Вы писали:
ВВ>>Все языки семейства ML тебя устроят? Scala? Haskell? Nemerle? T>В хаскеле точно нет ни void, ни unit.
Неправда, в Хаскеле есть тип unit.
T>Круто.
А что крутого? Последовательность исполнения тебе и C# не гарантирует.
T>(монада в общем смысле тоже не гарантирует кстати. Только IO)
Разве? Что-то ты путаешь, мне кажется.
T>Я хочу увидеть (и показать) как (в худшем случае) N-1 выражений в каждом блоке не используются.
Синтаксический мусор т.е.? Ну я и так знаю, что он есть.
T>add_1 :: Number -> Number T> x = x + 1
А как написать аналог такого:
let isEven(x) = x % 2 == 0;
let list = [1, 2, 3, 4, 5, 6];
... = filter(list, isEven);
Реализацию filter опускаем.
T>Можно убрать слово "функциональный" чтобы выглядело более естественно. Смысл не изменится, потому что всё есть функция. Думаю, что именно в этом и кроется смысл выражения "функциональный язык".
Может быть, это справедливо для Хаскеля (и то сомневаюсь), но для большинства других языков — нет. В ML все есть значение, но значение необязательно есть функция.
T>return сам по себе неплох. Просто нужно помнить, что он ещё и вызывает продолжение, т.е. по сути это name-bind + goto. Так вот, как минимум первая его половина — полезна очень.
Какой еще name-bind? Return без goto полностью аналогичен записи без return.
Я перепробовал много вариантов — с разделением на expression && statements, со злобными ошибками на некоторые из выражений и проч. — к текущему пришел далеко не сразу. Может быть, он неидеален, но это лучшее из того, что я перепробовал.
Здравствуйте, night beast, Вы писали:
NB>да я не спорю что не конфликтна NB>что должно быть про cond == false? выполняться только #2 или ничего
Ты, видимо, else пропустил. Вообще я все же не понимаю вопрос. Или ты намекаешь на то, что else — это не мусор? А на else никто и не наезжал. Но вот скобочки вокруг cond вполне могут быть и мусором.
Самая минимальная неконфликтная запись условия:
cond ? expr1 : expr2
NB>>>а почему бы не требовать ";" только в блоке кода? ВВ>>Не понял. NB>if (cond) { 1; 2; } -- хорошо NB>if (cond) { 1; 2 } -- плохо NB>ставить ли ; после } -- открытый вопрос.
Ну а что это меняет? А в глобальном блоке как быть? А как быть с конструкциями, которые вообще могут быть без блоков?
Здравствуйте, Воронков Василий, Вы писали:
NB>>да я не спорю что не конфликтна NB>>что должно быть про cond == false? выполняться только #2 или ничего
ВВ>Ты, видимо, else пропустил. Вообще я все же не понимаю вопрос. Или ты намекаешь на то, что else — это не мусор? А на else никто и не наезжал.
нет, там ";" после первого выражения пропущено.
ВВ>Но вот скобочки вокруг cond вполне могут быть и мусором.
class Test {
operator bool ();
operator () (int)
} test;
if test (1) ;
здесь ошибка или нет?
NB>>>>а почему бы не требовать ";" только в блоке кода? ВВ>>>Не понял. NB>>if (cond) { 1; 2; } -- хорошо NB>>if (cond) { 1; 2 } -- плохо NB>>ставить ли ; после } -- открытый вопрос.
ВВ>Ну а что это меняет? А в глобальном блоке как быть?
так же как в не глобальном.
ВВ> А как быть с конструкциями, которые вообще могут быть без блоков?
Здравствуйте, night beast, Вы писали:
ВВ>>Ты, видимо, else пропустил. Вообще я все же не понимаю вопрос. Или ты намекаешь на то, что else — это не мусор? А на else никто и не наезжал. NB>нет, там ";" после первого выражения пропущено.
Если запись expr expr не создает конфликтов, то все понятно. Ты записал в строку if без else и еще одно выражение.
ВВ>>Но вот скобочки вокруг cond вполне могут быть и мусором.
NB>
NB>class Test {
NB> operator bool ();
NB> operator () (int)
NB>} test;
NB>if test (1) ;
NB>
NB>здесь ошибка или нет?
Я вообще не вижу тут проблемы. Ну т.е. у всех конструкций есть вполне очевидное завершение. Ну и ; сам по себе является валидным выражением. Так что все в порядке.
ВВ>>Ну а что это меняет? А в глобальном блоке как быть? NB>так же как в не глобальном.
А вот тут точно нужны все точки с запятой:
x => { expr1; expr2; };
ВВ>> А как быть с конструкциями, которые вообще могут быть без блоков? NB>пример?
Что-то мне подсказывает, что два Console.Write выполнятся именно в том порядке, в котором они записаны.
T>>(монада в общем смысле тоже не гарантирует кстати. Только IO) ВВ>Разве? Что-то ты путаешь, мне кажется.
Монада это интерфейс из двух методов, вот и всё. Как видишь, про последовательность ничего.
Монада IO даёт последовательное вычисление. А тысячи остальных — нет. Потому что нигде, кроме IO оно и не нужно.
Ну или покажи где я путаю. В принципе, конечно, могу путать. Но тут уверен.
T>>Я хочу увидеть (и показать) как (в худшем случае) N-1 выражений в каждом блоке не используются. ВВ>Синтаксический мусор т.е.? Ну я и так знаю, что он есть.
Не синтаксический. как бы это.. семантический мусор что-ли
Грамматически в коде куча значений и не используются. Некрасиво. Вот стейтменты честно говорят, что значений они не возвращают. И for более логичен в виде стейтмента, чем в виде выражения со значением null/void/etc.
Это я всё почему... поставь себя на место компилятора. Не используется выражение? Ну так и не надо его вычислять. Логично.
T>>add_1 :: Number -> Number T>> x = x + 1
ВВ>А как написать аналог такого:
ВВ>
even x = x % 2 == 0
xs = list 1..6
ys = filter even xs
(я опять потерял нить по какому поводу этот код)
T>>Можно убрать слово "функциональный" чтобы выглядело более естественно. Смысл не изменится, потому что всё есть функция. Думаю, что именно в этом и кроется смысл выражения "функциональный язык".
ВВ>Может быть, это справедливо для Хаскеля (и то сомневаюсь), но для большинства других языков — нет. В ML все есть значение, но значение необязательно есть функция.
Это как-то в общей теории что-ли... в математике что-ли... значение тождественно нулларной функции, которая вернула бы это значение. У них смысловой разницы нет. Это в языках, где функцию надо явно *вызвать* чтобы получить её значение — разница появляется.
T>>return сам по себе неплох. Просто нужно помнить, что он ещё и вызывает продолжение, т.е. по сути это name-bind + goto. Так вот, как минимум первая его половина — полезна очень.
ВВ>Какой еще name-bind? Return без goto полностью аналогичен записи без return. ВВ>Я перепробовал много вариантов — с разделением на expression && statements, со злобными ошибками на некоторые из выражений и проч. — к текущему пришел далеко не сразу. Может быть, он неидеален, но это лучшее из того, что я перепробовал.
name-bind это присваивание результата вызова функции какому-то имени.
Например, снаружи код
print x + 1 # то есть функцию '+' вызвали с двумя аргументами
В этом месте можно представить виртуальное имя _expr_x+1
_expr_x+1 = x + 1
print _expr_x+1
Так вот, код оператора + мог бы быть примерно таким:
function op_+ (x, y) {
return _numeric_plus(x, y); # вот этот return делает присваивание результата _numeric_plus имени _expr_x+1 а ещё делает goto на следущую строку (то есть на строку с принтом)
}
Здравствуйте, Temoto, Вы писали:
T>Был микропроект по написанию парсера. На хаскеле T>Компилировать это отличный вопрос. На первом этапе, честно говоря, я собирался сделать интерпретатор, как более простой вариант. T>Но мечта идиота — компилить в LLVM IR.
Свой интерпретатор == своя виртуальная машина со своим байт-кодом. А это дает ряд преимуществ. Например, при дизайне байт-кода ты можешь фактически "заточить" его под особенности своего языка.
А вот если использовать LLVM, MSIL/JIT и проч., то тебе придется прогибаться под существующий дизайн. Например, MSIL — это объектно-ориентированный ассемблер и так далее.
Т.е. тут надо аккуратнее выбирать. Свой интерпретатор в чем-то сложнее, но в чем-то проще. Но можно получить нефиговое количество гемороя пытаясь потом портировать его под другую VM. Если уж мечта — это LLVM, то лучше сразу на ней и делать. К тому же рабочий прототип ты получишь раньше, чем с интерпретатором.
T>>Был микропроект по написанию парсера. На хаскеле T>>Компилировать это отличный вопрос. На первом этапе, честно говоря, я собирался сделать интерпретатор, как более простой вариант. T>>Но мечта идиота — компилить в LLVM IR.
ВВ>Свой интерпретатор == своя виртуальная машина со своим байт-кодом. А это дает ряд преимуществ. Например, при дизайне байт-кода ты можешь фактически "заточить" его под особенности своего языка. ВВ>А вот если использовать LLVM, MSIL/JIT и проч., то тебе придется прогибаться под существующий дизайн. Например, MSIL — это объектно-ориентированный ассемблер и так далее.
Да, я уже наслышан о геморе мужиков из Unladen Swallow. http://www.python.org/dev/peps/pep-3146/#id142 здесь описано подробно
ВВ>Т.е. тут надо аккуратнее выбирать. Свой интерпретатор в чем-то сложнее, но в чем-то проще. Но можно получить нефиговое количество гемороя пытаясь потом портировать его под другую VM. Если уж мечта — это LLVM, то лучше сразу на ней и делать. К тому же рабочий прототип ты получишь раньше, чем с интерпретатором.
И что это? unit в Хаскеле это пустой кортеж. Его литерал — это ()
T>>>Круто. ВВ>>А что крутого? Последовательность исполнения тебе и C# не гарантирует. T>Что-то мне подсказывает, что два Console.Write выполнятся именно в том порядке, в котором они записаны.
А если еще вспомнить, что даже в C# есть ленивость:
var list = ....;
var seq = from p in list select p;
...
много кода
...
foreach (var s in seq) {}//а вот тут выполняется select
T>>>(монада в общем смысле тоже не гарантирует кстати. Только IO) ВВ>>Разве? Что-то ты путаешь, мне кажется. T>Монада это интерфейс из двух методов, вот и всё. Как видишь, про последовательность ничего.
Монада это — сначала функция А, потом функция Б. Описание функции Б выглядит как "сначала функция А1, потом функция Б2".
По-моему — четкая последовательность.
T>>>Я хочу увидеть (и показать) как (в худшем случае) N-1 выражений в каждом блоке не используются. ВВ>>Синтаксический мусор т.е.? Ну я и так знаю, что он есть.
T>Не синтаксический. как бы это.. семантический мусор что-ли T>Грамматически в коде куча значений и не используются. Некрасиво. Вот стейтменты честно говорят, что значений они не возвращают.
Альтернатива приведет к тому, что ты будешь постоянно писать что-то типа:
let func(..) = {
for (...) {
}
null;
};
Я через это уже проходил, некрасивости куда больше.
Да и что такого некрасивого в void? Это просто значение, которого нет.
T>И for более логичен в виде стейтмента, чем в виде выражения со значением null/void/etc.
Ты знаешь как переводится слово void? Пусто. Нету тут ничего, это void. В выражении:
for (...) {
}
Никаких значений тут не создается и ничего не стек не поднимается.
T>Это я всё почему... поставь себя на место компилятора. Не используется выражение? Ну так и не надо его вычислять. Логично.
Не совсем. Не использует *возвращаемое значение* выражения. В коде вида:
func(...);
Возвращаемое значение тоже не используется, но функция вполне может делать что-нибудь полезное. С сайд-эффектами
Не вызывать ее?
T>even x = x % 2 == 0 T>xs = list 1..6 T>ys = filter even xs
T>(я опять потерял нить по какому поводу этот код)
Ни по какому. Просто хочется лучше понять, что ты придумал.
T>Это как-то в общей теории что-ли... в математике что-ли... значение тождественно нулларной функции, которая вернула бы это значение. У них смысловой разницы нет. Это в языках, где функцию надо явно *вызвать* чтобы получить её значение — разница появляется.
Это в чистых ленивых языках. Тут "функциональность" сама по себе не причем, если ты конечно ее с ленивостью не делаешь тождественной.
Выражение вида
x = 2 + 2
становится функцией именно потому что оно будет вычислено только когда реально потребуется.
Но большая часть остальных языков — вполне себе энергичные. Да еще и с побочными эффектами. Там нельзя делать такую "прозрачную" ленивость.
T>name-bind это присваивание результата вызова функции какому-то имени.
Ну это не return делает. Это делает, например, let binding:
let func() = (0, 1, 2);
let (x, y, z) = func();
Этот код мог выглядеть и так:
let func() = return (0, 1, 2);
let (x, y, z) = func();
Как видишь ничего не меняется.
А вот goto — да, это return.
А собственный компилятор в уже существующий бэкенд, это:
1. Парсер (1 штука)
2. Компилятор (1 штука)
Я не знаком конкретно с LLVM, но я не думаю, что тут ситуация кардинально отличается от .NET. Суть в том, что уже есть готовый бэкенд и есть некий набор инструкций, который на нем выполняется. Для обкатки каких-то решений, конечно, проще, когда все это уже есть. Если идти глубже, то да — может оказаться, что существующий бэкенд в чем-то ограничен, не совсем подходить, и надо будет пытаться обходить его ограничения и особенности.
Но мне кажется, для того чтобы получить из концепции на бумаге что-то работающее — это все же путь более прямой, хоть конечно сильно зависит от языка и твоих задумок.
Со своей вирт. машиной — если все же задача сделать что-то реально полезное, с приемлимой производительностью — можно много времени убить именно на ее тюнинг. Плюс ты *все* делаешь сам. Например, в случае с MSIL-ом в качестве бэкенда реализация какого-нибудь try/catch/finally — дело плевое. Оно уже есть там. Если делать самому — то это нефиговая такая задача.
Ну и честно говоря мне кажется на Хаскеле сложновато будет написать быструю вирт. машину, сравнимую по производительности с реализациями на том же Си. А скорость все же важна.
Ах вон ты о чём. Теперь понял.
T>>>>Круто. ВВ>>>А что крутого? Последовательность исполнения тебе и C# не гарантирует. T>>Что-то мне подсказывает, что два Console.Write выполнятся именно в том порядке, в котором они записаны.
ВВ>Ерунда.
ВВ>
А причём тут гарантия последовательности? Я сказал про два Console.Write, а не про два Console.Write с кучей goto.
ВВ>А если еще вспомнить, что даже в C# есть ленивость:
А ленивость, ещё раз, к последовательности отношения не имеет. Можно выполнить последовательно и потом. Можно выполнить в разнобой и сейчас.
ВВ>Монада это — сначала функция А, потом функция Б. Описание функции Б выглядит как "сначала функция А1, потом функция Б2". ВВ>По-моему — четкая последовательность.
Хакей, мы по-разному понимаем этот термин. Думаю, что тебе стоит обратиться к какому-нибудь штангисту и уточнить своё определение.
T>>>>Я хочу увидеть (и показать) как (в худшем случае) N-1 выражений в каждом блоке не используются. ВВ>>>Синтаксический мусор т.е.? Ну я и так знаю, что он есть. T>>Не синтаксический. как бы это.. семантический мусор что-ли T>>Грамматически в коде куча значений и не используются. Некрасиво. Вот стейтменты честно говорят, что значений они не возвращают. ВВ>Альтернатива приведет к тому, что ты будешь постоянно писать что-то типа: ВВ>Я через это уже проходил, некрасивости куда больше.
Согласен, некрасиво. Потому что это не альтернатива. Это просто зачем-то явный null в конце. А неиспользованное выражение for осталось.
ВВ>Да и что такого некрасивого в void? Это просто значение, которого нет.
Именно это и некрасиво. Значение, которое ничего не значит. Охренеть содержательно. Если б оно называлось side-effect, было бы честнее и понятнее, чес-слово.
T>>Это я всё почему... поставь себя на место компилятора. Не используется выражение? Ну так и не надо его вычислять. Логично. ВВ>Не совсем. Не использует *возвращаемое значение* выражения. В коде вида:
ВВ>
ВВ>func(...);
ВВ>
ВВ>Возвращаемое значение тоже не используется, но функция вполне может делать что-нибудь полезное. С сайд-эффектами ВВ>Не вызывать ее?
Я повторюсь, что лично по-моему, стейтмент это и есть "выражение, значение которого неважно, но вычислить его нужно".
T>>Это как-то в общей теории что-ли... в математике что-ли... значение тождественно нулларной функции, которая вернула бы это значение. У них смысловой разницы нет. Это в языках, где функцию надо явно *вызвать* чтобы получить её значение — разница появляется.
ВВ>Это в чистых ленивых языках. Тут "функциональность" сама по себе не причем, если ты конечно ее с ленивостью не делаешь тождественной.
Я даже чётко написал, что это не в языках программирования вообще.
ВВ>Выражение вида
ВВ>x = 2 + 2
ВВ>становится функцией именно потому что оно будет вычислено только когда реально потребуется. ВВ>Но большая часть остальных языков — вполне себе энергичные. Да еще и с побочными эффектами. Там нельзя делать такую "прозрачную" ленивость.
Где побочных эффектов нет, там и можно, почему же. А наличие побочных эффектов во многих случаях можно статически найти. Тут рядом это обсуждалось в контексте немерле.
T>>name-bind это присваивание результата вызова функции какому-то имени.
ВВ>Ну это не return делает. Это делает, например, let binding:
ВВ>Как видишь ничего не меняется. ВВ>А вот goto — да, это return.
Почему return этого не делает ты не сказал. Или может return в Ela этого не делает — то, конечно, всё может быть, я не знаю внутренностей. Опять, я рассуждаю с позиции какой-то теории не в конкретном языке, а в целом.
Хакей, не сошлись терминами. У меня немного другая мысль была.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, Temoto, Вы писали:
T>>Почему рабочий прототип на LLVM раньше?
ВВ>Если подходить к вопросу сугубо формально, то собственный интерпретатор — это:
ВВ>1. Парсер (1 штука) ВВ>2. Компилятор (1 штука) ВВ>3. Виртуальная машина (1 штука)
ВВ>А собственный компилятор в уже существующий бэкенд, это:
ВВ>1. Парсер (1 штука) ВВ>2. Компилятор (1 штука)
ВВ>Я не знаком конкретно с LLVM, но я не думаю, что тут ситуация кардинально отличается от .NET. Суть в том, что уже есть готовый бэкенд и есть некий набор инструкций, который на нем выполняется. Для обкатки каких-то решений, конечно, проще, когда все это уже есть. Если идти глубже, то да — может оказаться, что существующий бэкенд в чем-то ограничен, не совсем подходить, и надо будет пытаться обходить его ограничения и особенности. ВВ>Но мне кажется, для того чтобы получить из концепции на бумаге что-то работающее — это все же путь более прямой, хоть конечно сильно зависит от языка и твоих задумок.
ВВ>Со своей вирт. машиной — если все же задача сделать что-то реально полезное, с приемлимой производительностью — можно много времени убить именно на ее тюнинг. Плюс ты *все* делаешь сам. Например, в случае с MSIL-ом в качестве бэкенда реализация какого-нибудь try/catch/finally — дело плевое. Оно уже есть там. Если делать самому — то это нефиговая такая задача.
Понял. Если подходить формально, то конечно, 3 компонента больше, чем 2
ВВ>Ну и честно говоря мне кажется на Хаскеле сложновато будет написать быструю вирт. машину, сравнимую по производительности с реализациями на том же Си. А скорость все же важна.
По-моему, люди часто путают "скорость важна" и "нужна скорость близкая к бесконечности". Как там было... (маленькое число по вкусу) кода выполняется (большое число) времени. Всё остальное оптимизировать смысла нет.