Для хардкорной математики очень нужны странные фичи
1. Именованные туплы, а лучше именование параметров Generic'ов:
func() : (a:int * b:int * color:int)
{
def x = new { a = 5, b = 20, color=30 };//тут по пальцам если вместо a и b указаны x и y, идеально если ещё и порядок не важен
x;
}
//использованиеdef r = func();
Console.WriteLine(r.a);
Console.WriteLine(r.b);
Console.WriteLine(r.color);
Основная цель этой фичи — не завязываться на порядок возвращаемых значений ни в самой функции, которая может быть очень большой, ни вне её, а работать только с именами.
2. Сильная типизация алиасов, с типизацией индексов массивов:
type Idx = int;
type Idy = int;
type Idz = int;
//объявление двумерного ступенчатого массива, с индексаторами Idx, Idy и типом значения Idzdef a : array[(dimension1 : Idx) array[(dimension2 : Idy) Idz]];
//тут компилятор даст по пальцам, т.к. у массива типы не int
a[5][10] = 20;
//тут ок, т.к. у массива индексаторы правильных типов, и значение тоже правильного типа
a[5:Idx][10:Idy] = 20:Idz;
def iX = 1 : Idx;
def iY = 2 : Idy;
//с этого момента iX и iY - самостоятельные типы,
//которые к int приводятся только через операторы : и :>
//соответственно встроенные операторы сложения вычитания и т.п.
//тоже начинают понимать только значения правильного типа
Console.WriteLine(a[iX][iX]);//ошибка компиляции, второй индекс должен быть типа Idx;
Console.WriteLine(a[iX][iY]);//всё ок
Цель — снижение числа трудных математических ошибок. У математиков индексов много, каждый индекс нельзя путать с другими. Они важны, как в физике размерности. Ошибки индексации могут быть совершенно неочевидны, и ловить их черезвычайно сложно.
Интересует, в каком направлении копать, и насколько сложно эти две задачи реализовать в Н1 (пусть даже ценой поддержания собственной версии компилятора, если больше никому не надо). И огромная просьба учесть нужность этих фич для системы типов Н2.
Также буду благодарен за критику и возможные идеи в данных направлениях.
Здравствуйте, hi_octane, Вы писали:
_>И огромная просьба учесть нужность этих фич для системы типов Н2.
У меня есть кое какие мысли по расширяемой системе типов чтобы можно было делать произвольные статически типизированные ДСЛ.
Скажем тот же ПЕГ парсер был бы проще и лучше бы интегрировался с ИДЕ если бы я мог расширить систему типов так чтобы немерле смог выводить типы для правил.
Также можно будет сделать dynamic из C# просто расширением системы типов.
Но пока я разбираюсь с парсером.
Там есть еще куча всего что я хочу сделать.
Это касается как функциональности так и оптимизаций (я знаю как сделать его еще быстрее ).
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Именованные туплы и более типизированные массивы
От:
Аноним
Дата:
14.02.11 16:55
Оценка:
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, hi_octane, Вы писали:
_>>И огромная просьба учесть нужность этих фич для системы типов Н2. WH>У меня есть кое какие мысли по расширяемой системе типов чтобы можно было делать произвольные статически типизированные ДСЛ. WH>Скажем тот же ПЕГ парсер был бы проще и лучше бы интегрировался с ИДЕ если бы я мог расширить систему типов так чтобы немерле смог выводить типы для правил. WH>Также можно будет сделать dynamic из C# просто расширением системы типов. WH>Но пока я разбираюсь с парсером. WH>Там есть еще куча всего что я хочу сделать. WH>Это касается как функциональности так и оптимизаций (я знаю как сделать его еще быстрее ).
Разве вывод типов не сделает их эквивалентными?
Re[3]: Именованные туплы и более типизированные массивы
Здравствуйте, <Аноним>, Вы писали:
А>Разве механизм вывода типов не сделает типы эквивалентными в примере ТС.
Если он будет знать про "сильные алиасы" то конечно нет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Именованные туплы и более типизированные массивы
От:
Аноним
Дата:
14.02.11 18:07
Оценка:
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, <Аноним>, Вы писали:
А>>Разве механизм вывода типов не сделает типы эквивалентными в примере ТС. WH>Если он будет знать про "сильные алиасы" то конечно нет.
а разве в немерли есть сильные алиасы?
Re[2]: Именованные туплы и более типизированные массивы
Здравствуйте, WolfHound, Вы писали:
_>>И огромная просьба учесть нужность этих фич для системы типов Н2. WH>У меня есть кое какие мысли по расширяемой системе типов чтобы можно было делать произвольные статически типизированные ДСЛ.
Так ты прежде чем делать, какой диз-док опубликуй, ибо необходимость расширять типы есть, причём расширять даже в тех местах где .NET вроде как не позволяет (тот же мой пример с типизацией Array). А как правильно сделать — можно придумать только рассмотрев как можно больше сценариев использования. Например мне в проекте ещё нужны виртуальные наследники, которые существуют только в уме у компилятора, а в IL от них остаются только базовые классы. Ту же типизацию индексаторов можно было бы сделать создав виртуального наследника от массива, у которого индексаторы были бы типизированы, но на последнем этапе компиляции подменялись бы на реальные типы.
WH>Скажем тот же ПЕГ парсер был бы проще и лучше бы интегрировался с ИДЕ если бы я мог расширить систему типов так чтобы немерле смог выводить типы для правил. WH>Также можно будет сделать dynamic из C# просто расширением системы типов.
dynamic малость ущербен — у него не может быть интеллисенса и compile-time валидации. Более правильно было бы сделать dynamic псевдо-типизируемым дженериком. Например:
def d = obj : dynamic<IList>;
d.|/* <- тут автокомплит показывает методы и свойства IList,
есть проверка синтаксиса, аргументов, и т.п. При этом компилятор ругается на попытки
сделать что-то за пределами IList. Но это не кастинг, вызовы идут обычным
механизмом динамиков, т.е. obj вполне может от всего IList поддерживать только Count.*/
Это кстати тоже кусочек системы типов. Когда тип виртуально есть, а реально вместо него object запечёный с сахаром.
WH>Там есть еще куча всего что я хочу сделать. WH>Это касается как функциональности так и оптимизаций (я знаю как сделать его еще быстрее ).
Имхо логично сделать сначала медленный парсер, но чтоб его начали прикручивать к Н2 пораньше, а ускорять уже в процессе. Но, полагаю, ты это и без меня прекрасно знаешь
Re[3]: Именованные туплы и более типизированные массивы
Здравствуйте, hi_octane, Вы писали:
_>Так ты прежде чем делать, какой диз-док опубликуй, ибо необходимость расширять типы есть, причём расширять даже в тех местах где .NET вроде как не позволяет (тот же мой пример с типизацией Array).
Опубликую конечно. Просто от мыслей до диздока...
Все что ты понаписал моим мыслям не противоречит.
_>Имхо логично сделать сначала медленный парсер, но чтоб его начали прикручивать к Н2 пораньше, а ускорять уже в процессе. Но, полагаю, ты это и без меня прекрасно знаешь
Ну я так и делаю.
Правда он у меня уже очень даже не медленный. А будет еще быстрее.
Одна из мыслей дать пользователю возможность давать компилятору хинты на тему какие символы в данном месте всречаются чаще.
Например этот код генерирует ужасающее колличество проверок:
Хоть я и сделел генерацию бинарного поиска но всеравно много. Плюс код толстый -> промахи кеша.
При этом в подавляющем большенстве случаев этот код не встретит ничего кроме латинских букв, цифр и "_".
И если правило переписать так:
Здравствуйте, hi_octane, Вы писали:
_>Для хардкорной математики очень нужны странные фичи
_>1. Именованные туплы, а лучше именование параметров Generic'ов:
_>
_>func() : (a:int * b:int * color:int)
_>{
_> def x = new { a = 5, b = 20, color=30 };//тут по пальцам если вместо a и b указаны x и y, идеально если ещё и порядок не важен_> x;
_>}
_>//использование_>def r = func();
_>Console.WriteLine(r.a);
_>Console.WriteLine(r.b);
_>Console.WriteLine(r.color);
_>
_>Основная цель этой фичи — не завязываться на порядок возвращаемых значений ни в самой функции, которая может быть очень большой, ни вне её, а работать только с именами.
[Record]
class R
{
public A : int { get; }
public B : int { get; }
public Color : int { get; }
}
def f() : R
{
def x = R(a = 5, b = 20, color = 30);
x
}
Чем такой вариант не устраивает ?
Как вариант можно еще укоротить макросом скажем наподобие:
[assembly: DefineRecord(A : int, B : int, Color : int)]
А если значение функции используется локально, то проще тогда уже просто тупл вернуть
__>def f() : R
__>{
__> def x = R(a = 5, b = 20, color = 30);
__> x
__>}
__>
__>Чем такой вариант не устраивает?
Математики от меня наглядности требуют. В случае если таких методов штук 20 наберётся — получится столько-же Record'ов, и все с одной лишь целью — вернуть значение или список значений. Наглядность за этим R для них теряется. Тупл тоже отклоняют — завязываться на порядок аргументов или возвращаемых значений для них смерти подобно.
Про варианты объявления Record'а макросом я много думал, и пробовал. Думал также расширить макрос IAnonymous, таким образом чтобы он возвращал наследника от IAnonymous, с объявленными пропертями. Но нужно максимально информативное и объявление функции и использование её результата. Основная проблема, судя по всему, в объявлении, где нужно смешать и имена и типы, а имён в типе возвращаемого значения сейчас никто не ждёт. Вот это и хочется победить. Record был бы идеален, если бы объявлялся непосредственно как возвращаемое значение функции.
В общем основной вопрос, действительно ли сложно допилить компилятор таким образом, чтобы при разборе туплов расширенная информация о типах и именах скармливалась в какой-то макрос, который бы это разбирал, создавал нужный рекорд на уровне сборке, и далее по образу и подобию IAnonymous. Пока эта задача не выглядит простой, но я очень давно в компилятор не заглядывал, вот и хочу получить напутствие... может там на 3 человеко-месяца рефакторинг, и лучше эти силы вложить в помощь в разработке этих же фич но для Н2.
Re: Именованные туплы и более типизированные массивы
Здравствуйте, hi_octane, Вы писали:
_>Для хардкорной математики очень нужны странные фичи
_>1. Именованные туплы, а лучше именование параметров Generic'ов:
_>
_>func() : (a:int * b:int * color:int)
_>{
_> def x = new { a = 5, b = 20, color=30 };//тут по пальцам если вместо a и b указаны x и y, идеально если ещё и порядок не важен_> x; // по пальцам будет тут конечно_>}
_>
_>Основная цель этой фичи — не завязываться на порядок возвращаемых значений ни в самой функции, которая может быть очень большой, ни вне её, а работать только с именами.
Фича отличная, нужна. Вообще нужен эффективный duck typing, с ним это реализуется легко.
_>2. Сильная типизация алиасов, с типизацией индексов массивов: _>
_>type Idx = int;
_>type Idy = int;
_>type Idz = int;
_>//объявление двумерного ступенчатого массива, с индексаторами Idx, Idy и типом значения Idz_>def a : array[(dimension1 : Idx) array[(dimension2 : Idy) Idz]];
_>
Фича спорная, до ума ее довести довольно сложно.
Re[3]: Именованные туплы и более типизированные массивы
_>//тут компилятор даст по пальцам, т.к. у массива типы не int_>a[5][10] = 20;
_>//тут ок, т.к. у массива индексаторы правильных типов, и значение тоже правильного типа_>a[5:Idx][10:Idy] = 20:Idz;
можно зделать так:
enum Idx : int {}
class MyList[Tindex,Tval]
where Tindex : int
{
_l : List[Tval] = List();
public Item[index : Tindex] : Tval // опускаю все методы кроме индексатора
{ // потому что пример чисто
get
{
_l[index]
}
set
{
_l[index] = value;
}
}
}
и использование:
def l = MyList.[int,int]();
l[0] = 5;
def l = MyList.[Idx,int](); // Тут почему то дает ошибку: Error: expected int+, got Nemrrrr.Idx in generic specifier: Nemrrrr.Idx is not a subtype of System.Int32 [simple require]
l[0 :> Idx] = 5; // если убрать where Tindex : int то эта строчка работает
Думаю если пофиксить выведение типов для структур то это будет вполне реализуемо!
Re[2]: Именованные туплы и более типизированные массивы
__>Я полагаю , что это как раз можно сделать с метаатрибутом. __>Знающие люди подскажут насколько такое реально сделать.
Да такой вариант возможен, но уже после того как я эту ветку начал, удалось дотумкать ещё до одного вида, который сейчас кажется достаточно простым в реализации, и при этом сохраняет все плюшки автокомплита и интеллисенса:
[ExpandToRecord]
Func(a : int, b : bool, out c : int, out m : decimal) : void
{
//здесь компилятор искаропки проследит чтобы возвращаемые значения были правильно заданы, и т.п.
}
//а аттрибут создаёт пару типов AB и CM, и различные версии функции, которые вызывают основную
Func(ab : AB) : CM
{
def cm = CM();
Func(ab.a, ab.b, out cm.c, out cm.m);
cm;
}
Func(ab : AB, out c : int, out m : decimal) : void
{
}
Func(a : int, b : bool) : CM
{
}
Получив кучу версий, можно весьма свободно управлять данными, и при этом иметь автокомплит, интеллисенс, вывод типов и прочие. И, судя по всему, вообще не меняя ничего в компиляторе.
Но вот как быть с типизированными индексами массивов пока не знаю Частную задачу из одних массивов решать не хочется. Круто было бы если бы удалось совместно с кем-то продумать и ввести в язык "макротипы", которые ведут себя совсем как настоящие, но на какой-то из последних стадий разворачиваются в то, во что сами решат. Но тут нужно тотальную ревизию понятия "тип" проводить, и не факт что я с этим справлюсь.
Re[5]: Именованные туплы и более типизированные массивы
Здравствуйте, hi_octane, Вы писали:
__>>Я полагаю , что это как раз можно сделать с метаатрибутом. __>>Знающие люди подскажут насколько такое реально сделать.
_>Да такой вариант возможен, но уже после того как я эту ветку начал, удалось дотумкать ещё до одного вида, который сейчас кажется достаточно простым в реализации, и при этом сохраняет все плюшки автокомплита и интеллисенса:
_>
_>[ExpandToRecord]
_>Func(a : int, b : bool, out c : int, out m : decimal) : void
_>{
_>//здесь компилятор искаропки проследит чтобы возвращаемые значения были правильно заданы, и т.п._>}
_>//а аттрибут создаёт пару типов AB и CM, и различные версии функции, которые вызывают основную_>Func(ab : AB) : CM
_>{
_> def cm = CM();
_> Func(ab.a, ab.b, out cm.c, out cm.m);
_> cm;
_>}
_>Func(ab : AB, out c : int, out m : decimal) : void
_>{
_>}
_>Func(a : int, b : bool) : CM
_>{
_>}
_>
На самом деле макрос может изменять тип возврата... и возможно типы параметров, только там нужно применить магию со стадиями компиляции.
_>Получив кучу версий, можно весьма свободно управлять данными, и при этом иметь автокомплит, интеллисенс, вывод типов и прочие. И, судя по всему, вообще не меняя ничего в компиляторе.
_>Но вот как быть с типизированными индексами массивов пока не знаю Частную задачу из одних массивов решать не хочется. Круто было бы если бы удалось совместно с кем-то продумать и ввести в язык "макротипы", которые ведут себя совсем как настоящие, но на какой-то из последних стадий разворачиваются в то, во что сами решат. Но тут нужно тотальную ревизию понятия "тип" проводить, и не факт что я с этим справлюсь.
ОООо идея с макротипамми это +100 !!
Re[2]: Именованные туплы и более типизированные массивы
Оказалось это ограничение фреймворка, енум хоть и написано что от инта наследуется но он наследуется от енума на самом деле.
Вот рабочий пример:
public enum Idx : int {}
public class MyList[Tindex,Tval]
where Tindex : ValueType
{
static this()
{
def typ = typeof(Tindex);
unless (typ.Equals(typeof(int)) || typ.IsEnum)
throw System.ArgumentException();
}
_l : array[Tval];
public this(size : int)
{
_l = array(size);
}
public Item[index : Tindex] : Tval
{
get
{
_l[index :> int]
}
set
{
_l[index :> int] = value;
}
}
}
def l = MyList.[int,int](5);
l[0] = 5;
def l = MyList.[Idx,int](5);
l[1 :> Idx] = 5;
def l = MyList.[double,int](5); // тут будет Ексепшн, что тип недопустим
Re: Именованные туплы и более типизированные массивы
А как это должно работать ?
Т.е. что вы хотите конкретно получить ? Возможно это не получится сделать.
Теоретически можно сделать макрос, который создаст класс с операцией приведения типа и с дублированнием всех методов из заданного типа:
strong type Idx = int;
=>
class Idx
{
_value : int;
public this() { }
public this(value : int) { _value = value; }
public static @:(o : Idx) : int { _value; }
... // Тут уже надо думать что и как делать
}
Сделать, чтобы работало хотя бы для базовых типов.
Как я понимаю этого вам будет достаточно.