Re[26]: Мифический Haskell
От: vdimas Россия  
Дата: 03.04.12 10:09
Оценка:
Здравствуйте, VoidEx, Вы писали:


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


VE>Т.е. если я понимаю причинно-следственные связи характеристик языка, то ругать уже не буду вне зависимости от того, нравятся мне такие характеристики или нет? Интересное мнение.


Ес-но, если тебе некие характеристики языка не важны, но они, в свою очередь являются определяющими для системы типов, возможной в этих характеристиках, то надо брать другой язык. Т.е. сам смори что тебе первично — система типов инструментария или характеристики порождаемого инструментарием результата.
Re[31]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 10:18
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, VoidEx, Вы писали:


VE>>Тогда if-else тоже динамическая типизация.


V>Если при этом проверяется внутреннее устройство данных, то бишь их тип — несомненно.


Т.е. всегда. Ибо в чём фундаментальное отличие нижеприведённых примеров?

if (x < 0)
  foo1(x) // x is (a:int){a<0}
else
  foo2(x) // x is (a:int){a>=0}


if (isChild1(p))
  foo3(p) // x is Child1*
else
  foo4(p) // x is Child2*


Вы могли бы сказать, что в первом случае у нас используется само число, в во втором доступ к членам, но
1. Это далеко не всегда так, может, foo3 и foo4 этот указатель в списки добавляют
2. Разницы всё равно нет, так как foo1 и foo2 могут на основе значения бегать по таблицам, использовать числа как смещения и т.п. Грубо говоря вообще можно написать такой код, что foo1 и foo2 будут через таблицы эмулировать доступы в объектам.

VE>>Во-первых, как это нету?


V>Так что нету. Потому что нет параметризации типов константами и нет compile-time диспетчеризации по этим константам и нет частичного или явного инстанциирования шаблонных типов для конкретных комбинаций аргументов. Есть только такое инстанциирование для ф-ий.


Чой-то нету-то? Там вообще макросы есть, если что.

VE>>Во-вторых, можно пример, когда static_if не является сам по себе костылём?


V>Ха. Тогда любая статическая система типов — это костыль сам по себе, т.к. это способ перенести ограничения прикладной логики на компилятор.


Неверное обобщение. Если static_if используется для диспетчеризации, то для этого есть и другие механизмы. При этом с учётом того, что в Haskell никто не использует static_if, есть основания полагать, что все use-case покрываются другими средствами. Причём тут вся статическая типизация — не ясно.

V>Я могу спросить в ответ привести пример, когда классы типов Хаскеля не являются костылем?

А они костыль.
Re[14]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 10:21
Оценка:
Здравствуйте, DarkGray, Вы писали:


VE>>Можно пример в псевдокоде? Как предполагается это указывать?


DG>вообще, что интересует? нотация, какая-то часть семантики?


Какие типы "грязи" предлагаются? Зависимость от конкретной внешней переменной? Использование состояние? Ввод-вывод?
Вроде как в Disciple все функции могут иметь эффект, причём выводимый автоматически. Например putStrLn там имеет тип что-то вроде String -{!Console}-> ()
При этом в обычном коде это {!Console} писать не надо, хотя можно.

Посмотрите по ссылке (я выше давал), скажите, в чём не сходится с вашим представлением.
Re[32]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 10:41
Оценка:
VE>Т.е. всегда. Ибо в чём фундаментальное отличие нижеприведённых примеров?

вроде о том и речь, что ПМ это лишь красивый сахар для последовательности if/else-ов
Re[33]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 10:53
Оценка:
Здравствуйте, DarkGray, Вы писали:


VE>>Т.е. всегда. Ибо в чём фундаментальное отличие нижеприведённых примеров?


DG>вроде о том и речь, что ПМ это лишь красивый сахар для последовательности if/else-ов


Если смотреть с этой стороны, то с этим никто не спорит. Спорят с тем, что это что-то вроде динамической типизации. Проблема в том, что термин "типизация" тут как-то не определили.
Если смотреть в целом, то всё-таки нет, ибо паттерны могут быть вложенными, есть view-patterns, в Agda для функции, определённой через ПМ можно проводить доказательства (т.к. например для оператора сравнения будет существовать утверждение типа succ x == succ y = x == y), а через if-else будет значительно сложнее (т.к. приведённое выше утверждение уже отсутствует и им не попользуешься при доказательствах, его само сначала придётся доказать), и т.п.
Re[29]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 10:54
Оценка:
V>Я тебя спросил — покажи как это работает в рантайм? Ведь вызываемая затем ф-ия scalarProduct — рекурсивная, а глубина рекурсии заведомо неизвестна. Т.е. я понимаю твои предположения, если полностью раскрутить и переписать рекурсию, просчитав всё с конца списка. Давай тогда добавим побочный эффект в код scalarProduct, чтобы избежать этого. Думаю, добавление IO не должно сломать тайпчекер.

в данном случае речь о том, что scalarProduct в runtime-е будет следующим с гарантией, что First никогда не выкинет исключение, и что закоментированный if не нужен:
int scalarProduct(as, bs)
{
  //if(as == Nil && bs != Nil || as != Nil && bs == Nil)
  //  throw new Exception("длина списков не совпадает");
  if(as == Nil)
    return 0;
  return as.First() * bs.First() + scalarProduct(as.Tail(), bs.Tail());
}
Re[34]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 11:06
Оценка:
VE>Если смотреть с этой стороны, то с этим никто не спорит. Спорят с тем, что это что-то вроде динамической типизации. Проблема в том, что термин "типизация" тут как-то не определили.

в моем понимании, динамическая типизация — это когда в рантайме есть if на основе признака типа или виртуальный вызов на основе vtable типа. И то, и другое — роняет производительность.
а почти весь ПМ (при условии, что есть несколько веток) в это и транслируется.

VE>Если смотреть в целом, то всё-таки нет, ибо паттерны могут быть вложенными, есть view-patterns, в Agda для функции, определённой через ПМ можно проводить доказательства (т.к. например для оператора сравнения будет существовать утверждение типа succ x == succ y = x == y), а через if-else будет значительно сложнее (т.к. приведённое выше утверждение уже отсутствует и им не попользуешься при доказательствах, его само сначала придётся доказать), и т.п.


да, это всё есть и очень полезно, но динамическую типизацию уберет только в редких случаях
Re[15]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 11:11
Оценка:
VE>Посмотрите по ссылке (я выше давал), скажите, в чём не сходится с вашим представлением.

сходу не вижу примера самого интересного, когда при композиции та или иная грязь пропадает


VE> isNumber (needNoState rnd)


тут основной подвох, что необходимо сначала в нужное место вставить нужный needNoState, а потом при рефакторинге в:
isNumber-Больше-Одной-Второй(needNoState rnd)
не забыть его убрать.
те же явные касты (вид в профиль) с теми же последствиями
Re[16]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 11:29
Оценка:
Здравствуйте, DarkGray, Вы писали:


VE>>Посмотрите по ссылке (я выше давал), скажите, в чём не сходится с вашим представлением.


DG>сходу не вижу примера самого интересного, когда при композиции та или иная грязь пропадает


Не уверен, что там это есть. Тогда соответственно назревает вопрос. Как вы предлагаете проверять то, что грязь убирается?
Можно на таком примере: isEven (rnd * 2)
Ну или на ваш вкус

VE>> isNumber (needNoState rnd)


DG>тут основной подвох, что необходимо сначала в нужное место вставить нужный needNoState, а потом при рефакторинге в:

DG>isNumber-Больше-Одной-Второй(needNoState rnd)
DG>не забыть его убрать.
DG>те же явные касты (вид в профиль) с теми же последствиями

Явные касты — это благо. Именно потому, что при рефакторинге вас мордой ткнут и придётся убрать. А вот если молча проглотит, будет беда.
Re[35]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 11:37
Оценка: +2
Здравствуйте, DarkGray, Вы писали:


VE>>Если смотреть с этой стороны, то с этим никто не спорит. Спорят с тем, что это что-то вроде динамической типизации. Проблема в том, что термин "типизация" тут как-то не определили.


DG>в моем понимании, динамическая типизация — это когда в рантайме есть if на основе признака типа или виртуальный вызов на основе vtable типа. И то, и другое — роняет производительность.


Любой if — это вызов блока в if или блока в else на основе таблицы из true/false.

DG>а почти весь ПМ (при условии, что есть несколько веток) в это и транслируется.


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

То, что при наличии разных вариантов у АлгТД происходит ветвление — это динамическая типизация в той же мере, что и ветвление по 0 и не 0 в факториале. Назвать это динамической типизацией можно только при большой фантазии, да и то, с натяжкой.
С другой стороны динамическую типизацию можно было представить как кортеж из имени типа и значения.

Фундаментальную разницу я вижу в том, что при динамической типизации тип ровно один: dynamic.
Re[17]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 13:07
Оценка:
VE>Явные касты — это благо. Именно потому, что при рефакторинге вас мордой ткнут и придётся убрать. А вот если молча проглотит, будет беда.

говоря явный каст, я имел ввиду reinterpreted_cast или dynamic_cast, т.е. такой cast валидность которого не проверяется компилятором

извини, что сказал двусмысленно.

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

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

весь смысл статической типизации, что она может убирать if-ы

имея следующий код:
T Sum<T>(this IEnumerable<T> items)
{
  var sum = default(T);
  foreach (var item in items)
    sum = Sum(sum, item);
  return sum;
}
int Sum(int a, int b)
{
  return a + b;
}
double Sum(double a, double b)
{
  return a + b;
}
void Main()
{
  Enumerable.Range(1, 10).Sum().ToConsole();
}

при сильной статической типизации можно ожидать, что при исполнении будет следующий код без всяких if-ов:
Int Sum_Int(this IEnumerable<int> items)
{
  var sum = 0;
  foreach (var item in items)
    sum = Sum_Int(sum, item);
  return sum;
}
int Sum_Int(int a, int b)
{
  return a + b;
}
void Main()
{
  Enumerable.Range(1, 10).Sum_Int().ToConsole();
}

без статической типизации при исполнении не будет ничего лучше, чем следующий код:
object Sum(this items)
{
  var sum = null;
  foreach (var item in items)
    sum = Sum(sum, item);
  return sum;
}
object Sum(a, b)
{
  if (a is int && b is int)
    return (int)a + (int)b;
  if (a is double && b is double)
    return (double)a + (double)b;
  throw new Exception(..);
}
void Main()
{
  Enumerable.Range(1, 10).Sum().ToConsole();
}

данный код достаточно сильно тормозит по сравнению с предыдущим, потому что на каждой итерации идут проверки.
и я утверждаю, что ПМ в основном именно в такой тормозной код и разворачивается.
Re[18]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 13:36
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>весь смысл статической типизации, что она может убирать if-ы


Я бы сказал, что это побочный её эффект. Тем не менее в таком определении типизация не статическая или динамическая, а более или менее статическая.

В любой программе у нас так или иначе будут if'ы, без ветвлений ничего полезного не написать.
Мы могли бы ограничиться кортежами и целыми числами, и как будто бы и нет динамической типизации, но нам бы пришлось её эмулировать так или иначе через те самые if'ы.
АлгТД решает эту проблему. if при обработке АлгТД никуда не убрать, но его никуда не уберёшь в любой программе. Просто тут он в АлгТД, а там он был бы где-то ещё.

Тем не менее, в языке с зависимыми типами и теоремами и для АлгТД можно было бы выбрать ветку без if'а, но в частных случаях.
В общем, от ввода АлгТД "динамичности" не прибавляется, она просто перекочёвывает из if-else'ов в АлгТД, вот и всё.

DG>и я утверждаю, что ПМ в основном именно в такой тормозной код и разворачивается.


Нет. С ПМ у вас ровно первый вариант. Проверка на окончание итерирования аналогична проверке, Null ли список или Cons head tail. Функция суммирования же используется одна и никакого диспатча нет.

Я же утверждаю, что когда ПМ разворачивается в "такой тормозной код", то и без ПМ будет он же.
Основываюсь на том, что "хороший код" без ПМ можно перевести в код с ПМ, где классы перейдут в кортежи, а ветвления в варианты АлгТД (например nullable ссылки (ветвление по null и not-null) в Maybe).
Re[19]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 14:03
Оценка:
VE>Нет. С ПМ у вас ровно первый вариант. Проверка на окончание итерирования аналогична проверке, Null ли список или Cons head tail. Функция суммирования же используется одна и никакого диспатча нет.

VE>Я же утверждаю, что когда ПМ разворачивается в "такой тормозной код", то и без ПМ будет он же.


с этим утверждением не поспоришь, если брать в общем виде.

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

в тоже время я согласен, что теоретически в ПМ информации содержится больше, и его проще конвертнуть во что-нибудь хорошее.
Re[20]: Мифический Haskell
От: VoidEx  
Дата: 03.04.12 14:07
Оценка:
Здравствуйте, DarkGray, Вы писали:


VE>>Я же утверждаю, что когда ПМ разворачивается в "такой тормозной код", то и без ПМ будет он же.


DG>с этим утверждением не поспоришь, если брать в общем виде.


Не понимаю только, как после этой фразы вы пишете сразу же ей противоречащую:

DG>я больше говорил в разрезе, что если брать ПМ как он реализован в том же Haskell-е, то он будет генерить тормозной код, не сильно лучше, чем какая-нибудь динамика аля питон.


Нет, он будет генерить код не тормознее любой другой статики. Разумеется, не в абсолютной величине, а относительно обсуждаемого вопроса. Т.е. если статика а-ля C# обходится 10 if'ами, ПМ тоже обойдётся ими (с учётом тех, что в АлгТД).

DG>в тоже время я согласен, что теоретически в ПМ информации содержится больше, и его проще конвертнуть во что-нибудь хорошее.
Re[17]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.04.12 19:17
Оценка:
VE>Не уверен, что там это есть. Тогда соответственно назревает вопрос. Как вы предлагаете проверять то, что грязь убирается?
VE>Можно на таком примере: isEven (rnd * 2)

для функций isEven и '*' можно восстановить условные pre/post-conditions
//pre-condition even-integer => post-condition: true
//pre-condition odd-integer => post-condition: false
bool isEven(int i) {return i % 2 == 0;}

//pre-condition any(even-integer) => post-condition: even-integer
int operator *(int, int);


также для константы есть хитрый post-condition:
pre-condition:const-integer => post-condition:is-even(i) ? even-integer : odd-integer;


соответственно, на основе этих condition-ов для выражения isEven(rnd * 2) вообще вычисляется, что его post-condition: true
и что соответственно его можно заменить целиком на true при компиляции


VE>Ну или на ваш вкус


возьмем типичную ручную мемоизацию
class MyXY
{
  public MyXY(object x)
  {
    this.x = x;
  }
  readonly object x;
  
  public object Get()
  {
    if (_cache != null)
     _cache = Zzz.My(x);
    return _cache;
  }
  object _cache;
}

где Zzz.My — чистая функция возвращающая ненулевой результат
в этом коде Get.result = F(x, _cache, Zzz.My) и соответственно чистота(Get.result) = чистота(x) && чистота(_cache) && чистота(Zzz.My). x — чистая переменная, т.к. readonly, Zzz.My — чистая по определению, остался _cache.
_cache — может быть в двух состояниях: или null, или результат Zzz.My. Нулевое состояние _cache снаружи наблюдать(обнаружить) невозможно, т.к. для метода get: F(x, null, Zzz.My) == F(x, != null, Zzz.My), а других способов получить доступ к _cache нет.
Re[32]: Мифический Haskell
От: vdimas Россия  
Дата: 04.04.12 04:31
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Вы могли бы сказать, что в первом случае у нас используется само число, в во втором доступ к членам, но

VE>1. Это далеко не всегда так, может, foo3 и foo4 этот указатель в списки добавляют
VE>2. Разницы всё равно нет, так как foo1 и foo2 могут на основе значения бегать по таблицам, использовать числа как смещения и т.п. Грубо говоря вообще можно написать такой код, что foo1 и foo2 будут через таблицы эмулировать доступы в объектам.

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

V>>Я могу спросить в ответ привести пример, когда классы типов Хаскеля не являются костылем?

VE>А они костыль.

А что не так без них?

Дело в том, что С++ static_if в большинстве случаев не нужен, он удобен лишь для диагностики, остальное система типов С++ разруливает и так. Т.е. всё, что может быть описано через static_if, может быть описано и без него или даже не описано совсем, а получится "по факту". Т.е. это не костыль, а сахар. А вот классы типов — натуральный костыль, без которого многие трюки в Хаскеле просто не взлетят. А костыль это потому, что изначально в языке отсутствовала концепция контрактов/интерфейсов. И вот ее заменяет этот недокостыль. Исключительно из-за скудной системы типов, где все пользовательские типы данных — это АлгТД.
Re[34]: Мифический Haskell
От: vdimas Россия  
Дата: 04.04.12 04:41
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Если смотреть с этой стороны, то с этим никто не спорит. Спорят с тем, что это что-то вроде динамической типизации. Проблема в том, что термин "типизация" тут как-то не определили.


Определили. Это проверка/тестирование типа в рантайм.
Да и о чем спорить? По-определению АлгТД — это такой тип данных, в который упаковываются значения других типов. Вариант, он и в Африке вариант.

VE>Если смотреть в целом, то всё-таки нет, ибо паттерны могут быть вложенными, есть view-patterns, в Agda для функции, определённой через ПМ можно проводить доказательства (т.к. например для оператора сравнения будет существовать утверждение типа succ x == succ y = x == y), а через if-else будет значительно сложнее (т.к. приведённое выше утверждение уже отсутствует и им не попользуешься при доказательствах, его само сначала придётся доказать), и т.п.


Во-первых речь о Хаскеле, во вторых, Agda — это язык с зависимыми типами, у него типизация зависит от логических утверждений относительно значений в коде, в т.ч. от значений дискриминатора АлгТД. В любом случае, динамическая типизация никуда не девается. Просто ПМ по АлгТД — это такой встроенный трюк, что в конкретной ветке ПМ мы уже опять имеем статическую типизацию, но уже по фактическому выясненному содержимому АлгТД (а не по исходному, завернутому типу). Компилятор лишь гарантирует нам типобезопасность через отсутствие других способов реинтерпретировать память, занимаемую значениями АлгТД, кроме как через ПМ.
Re[36]: Мифический Haskell
От: vdimas Россия  
Дата: 04.04.12 04:57
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Любой if — это вызов блока в if или блока в else на основе таблицы из true/false.


В случае динамической типизации — не любой.


DG>>а почти весь ПМ (при условии, что есть несколько веток) в это и транслируется.

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

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

Т.е. имеем следующее: в compile-time пишем алгоритмы под все возможные (или уникально обрабатываемые) типы, ожидаемые в некоей точке алгоритма, а в рантайм через ветвление выбираем одну из веток алгоритма, согласно фактически поданному типу значения.

Для работоспособности этой схемы обязательно нужен некий механизм реинтерпретации памяти. Например, в C# это приведение типов as или через (Type1), в С++ через dynamic_cast или через reinterpret_cast, еще через встроенный рантайм-полиморфизм, в ML-языках через паттерн-матчинг.


VE>То, что при наличии разных вариантов у АлгТД происходит ветвление — это динамическая типизация в той же мере, что и ветвление по 0 и не 0 в факториале.


Нет.

VE>Назвать это динамической типизацией можно только при большой фантазии, да и то, с натяжкой.

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

Так и представляют, например АлгТД в Хаскеле. Разве что область значения нетипизирована в представлении, т.е. это просто область байт неизвестного содержания. Неизвестного до тех пор, пока не будет проверена метка типа.


VE>Фундаментальную разницу я вижу в том, что при динамической типизации тип ровно один: dynamic.


Чего?
Re[30]: Мифический Haskell
От: vdimas Россия  
Дата: 04.04.12 05:10
Оценка:
Здравствуйте, DarkGray, Вы писали:


V>>Я тебя спросил — покажи как это работает в рантайм? Ведь вызываемая затем ф-ия scalarProduct — рекурсивная, а глубина рекурсии заведомо неизвестна. Т.е. я понимаю твои предположения, если полностью раскрутить и переписать рекурсию, просчитав всё с конца списка. Давай тогда добавим побочный эффект в код scalarProduct, чтобы избежать этого. Думаю, добавление IO не должно сломать тайпчекер.


DG>в данном случае речь о том, что scalarProduct в runtime-е будет следующим с гарантией, что First никогда не выкинет исключение, и что закоментированный if не нужен:

DG>
DG>int scalarProduct(as, bs)
DG>{
DG>  //if(as == Nil && bs != Nil || as != Nil && bs == Nil)
DG>  //  throw new Exception("длина списков не совпадает");
DG>  if(as == Nil)
DG>    return 0;
DG>  return as.First() * bs.First() + scalarProduct(as.Tail(), bs.Tail());
DG>}
DG>


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

Знаешь какая ключевая фишка в обсуждаемом коде? Что Nil — это тип, независимый от Cons. Поэтому я и попросил кто может по-быстрому сгенерить сишный код компилятором, бо любопытно посмотреть диспетчеризацию по типам, не входящим в один АлгТД. Я ставлю на то, что компилятор унутре будет использовать ту же технику, что для обычных АлгТД, просто он объявит нужный алгТД сам, неявно.
Re[35]: Мифический Haskell
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 04.04.12 07:10
Оценка:
Здравствуйте, vdimas, Вы писали:

VE>>Спорят с тем, что это что-то вроде динамической типизации. Проблема в том, что термин "типизация" тут как-то не определили.


V>Определили. Это проверка/тестирование типа в рантайм.


Это фиговое и неправильное определение.
Типизация — это навешивание на каждое выражение в программе некоторого ярлыка-типа. Можем в компайл-тайме навесить достаточно конкретные типы на все — получили статическую типизацию. Не можем и вынуждены навешивать один неконкретный ярлык dynamic — получили динамическую.

V>Да и о чем спорить? По-определению АлгТД — это такой тип данных, в который упаковываются значения других типов. Вариант, он и в Африке вариант.


Это фиговое и неправильное определение, ведь "внутри" может оказаться он сам, не только "другие типы".
data Tree a = Leaf | Node a (Tree a) (Tree a)

Вариант так умеет?
й
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.