Re[36]: Проблемы организации OR-мапинга
От: vdimas Россия  
Дата: 28.04.09 12:43
Оценка: 2 (1)
Здравствуйте, 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>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.