Здравствуйте, EvilChild, Вы писали:
V>>В функцию приходит значение размеченного объединения, которое суть пара: разметка + значение соответсвующего разметке типа. Объекты CLR представлены в куче аналогично, кстати. И насчёт "одного типа"... в случае алгебраических типов мы имеем 2 типа минимум: тип группы и хоть один тип участника группы.
EC>Объясни мне тогда поведение GHCi:
EC>EC>*Main> :i MyNum
EC>data MyNum = One | Two
EC>*Main> :t One
EC>One :: MyNum
EC>*Main> :t Two
EC>Two :: MyNum
Для полноты картины надо было еще матчинг привести. В Хаскеле синтаксис минималистический — конструктор алгебраического типа выглядит так же как упоминание соотв. значения дискриминатора.
В этом примере One, Two — конструкторы алгебраического типа. Каждый из них конструирует обобщенный тип MyNum, заворачивая в него пустой тупл. Случай вырожденный, размеченное объединение для всех своих значений состоит из собс-но кода разметки и ничего более, т.е. такое использование близко к enum из C++ или C#.
V>>Не хочешь посмотреть на описание размеченных объединений в CORBA IDL и заодно посмотреть, что генерируют компиляторы на эти описания? А потом мы возьмем эти 3 примера: IDL, CLR и Хаскель, и посмотрим, что там происходит в процессе динамического определения типа.
EC>Хочу посмотреть, покажи.
Я предлагал тебе самому, но ладно.
Отрывок из произведений прошлых лет (IDL):
enum ScriptType {
eInstallExec,
eInstallCopy
};
union InstInfoBody switch(ScriptType) {
case eInstallExec: CommandExecInfoBody CommandExec;
case eInstallCopy: CopyInstallInfo CopyInstall;
};
В отличие от Хаскель дискриминатор описывается отдельно от объединения. Сомнительный бенефит в том, что зато его можно многократно исопльзовать.
CommandExecInfoBody и CopyInstallInfo — определенные выше в IDL типы (для нас не существенные).
В C# имеем (лишние подробности вырезал):
[Serializable, RepositoryID("IDL:EsdAgent/ScriptType:1.0"), IdlEnum]
public enum ScriptType
{
eInstallExec,
eInstallCopy
}
[Serializable, RepositoryID("IDL:EsdAgent/InstInfoBody:1.0"), IdlUnion]
public struct InstInfoBody : IIdlEntity, ISerializable
{
// Fields
private CommandExecInfoBody m_CommandExec;
private CopyInstallInfo m_CopyInstall;
private ScriptType m_discriminator;
// Methods
// приведу тело одного метода только
public CommandExecInfoBody GetCommandExec()
{
if (this.m_discriminator != ScriptType.eInstallExec)
throw new BAD_OPERATION(0x22, CompletionStatus.Completed_MayBe);
return this.m_CommandExec;
}
public CopyInstallInfo GetCopyInstall();
public void SetCommandExec(CommandExecInfoBody val);
public void SetCopyInstall(CopyInstallInfo val);
// Properties
public ScriptType Discriminator { get; }
}
Для С++ компилятором IDL генерируется аналогичная структура.
Как этим пользоваться в отсутствии паттерн-матчинга? Непосредственный switch/case по Discriminator:
switch(instInfoBody.Discriminator) {
case ScriptType.eInstallExec:
CommandExecInfoBody exec = instInfoBody.GetCommandExec();
...
break;
}
Теперь, если вернуться вообще к самому началу... В C# "дискриминатор" нам предоставляется самой CLR посредством GetType(). Он один на всех.

Как делать switch по типам, при отсутствии такой возможности в языке (если рассматривать обычные типы, а не генерённые IDL-компилятором)? Так же как и во всех других языках, где нет аналога swicth, т.е. через цепочки if/else.
Покажу для C++/CLR, т.к. там удобная возможность определения переменных и одновременной проверки на null:
if(Type1^ var1 = dynamic_cast<Type1>(obj)) {
// use var1 here ...
} else if (Type2^ var2 = dynamic_cast<Type2>(obj)) { ... }
} else { ... }
Если в паттерн матчинге оставить только одну строку, а все остальные варианты обозначить как "_", то как раз в аналогичный if/else и вырождается:
(не уверен в точности синтаксиса)
case obj of
(Type1 var1) -> ...
(_) -> case obj of
(Type2 var2) -> ...
(_) -> ...
Понятно, что матч по закрытой группе куда как более строг, чем по открытой и не требует генерации и обработки ошибочных ситуаций при динамическом приведении типов в рантайм (это Владу привет), но речь шла немного не об этом.
Да, алгебраические типы — очень удобная модель как раз для тех задач, где мы сегодня используем динамическое приведение в языках без оного. Внутренний механизм идентичен (даже для Хаскеля), но степень контроля компилятором значительно выше.
... << RSDN@Home 1.2.0 alpha rev. 786>>