Информация об изменениях

Сообщение Re[6]: Что должен возвращать if? от 20.10.2014 13:47

Изменено 20.10.2014 13:52 Evgeny.Panasyuk

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

G>В вашем случае, важна именно полноценная монада maybe. Паллиатив вида variant[T, void] — не даст вам возможности поймать "go wrong".


Почему же не даст? void тут играет роль Nothing.

G>И важен тут, не столько Nothing (который, вполне может быть заменен и на void),


Да, именно.

G>сколько Just. Т.е. если за-предикатное выражение вычисляется в T, то "нормальный" результат вычисления if-без-else будет Just[T], а не T.


Да, и я не вижу в этом проблемы.

G>Если теперь сравнить это с if-с-else, то видно следующее. Чтобы "в качестве результата можно использовать один тип результата" — в вашем случае — его придется вычислять в Just[T], а не в T. Что, вообще говоря, смысла лишено.


Почему же? Для обобщённого кода как раз и не лишено — вне зависимости от того, значения каких типов возвращают ветки if-else, всё выражение вычислится в Variant.
Для обычного, не обобщённого кода, да немного неудобно, но это обходится всего одним унарным оператором/унарной функцией, причём без потери производительности (Variant<T> всегда содержит внутри T, безусловно).

G>Даже если "обернуть" все это в variant — это мало что изменит . Типы A и Some[A] — это таки разные типы.

G>Можно потытаться "стереть границы" введя функторы, например... и вот тогда про "два синтаксиса" вообще никто вспоминать уж точно не будет

В случае когда у нас Variant<T>, полноценный функторный fmap не нужен, точнее можно без него. Достаточно T unbox(Variant<T> x);, или короткого оператора.

G>Смотрите, я выше высказался за разрешение неоднозначности при вычислении if-без-else. Действительно её можно снять вычисляя его в maybe. Проблема только в том, что это никакого отношения к вычислению if-с-else не имеет


Maybe действительно не имеет отношения, а вот Varaint — вполне.

G>Добиться "одинаковости" можно лишь вычислением и if-с-else тоже в maybe. Что весьма странно, согласитесь. Ведь никаких неоднозначностей при его вычмслении у нас нет. И никакие variant[A, B] и т.п. не дадут вам взаимозаменяемости, если хотите, между результатами вычислений if-с-else и if-без-else.


Почему же не дадут?

G>Вычисление if-с-else в variant, само по себе (без попытки добиться "симметрии") может иметь смысл. Но только в том случае, когда PM и использование variant уйдут на ступень выше, так сказать.


То есть основная проблема заключается в каких-то пробелах в Nemerle с Varaint'ом как таковым, а не в самой идеи if-else -> Variant?

G>Какой смысл в данный момент получать из if (который, на самом деле PM) variant? Для его обработки все равно придется использовать PM. Если же мы можем выделить общий интерфейс (т.е. при дальнейшей обработки обойтись без PM), то и возвращать из if лучше именно этот интерфейс. Что, как я понимаю, сейчас и делается.


Дело в том, что non-member функции также, грубо говоря, относятся к интерфейсу. Объектам необязательно иметь одинаковые-функции члены и общих предков, чтобы их можно было использовать с одинаковым синтаксисом.
Например на C++ можно вот так:
Variant<Widget, Gadget> x, y;
// ...
apply(x, y, [](auto &x, auto &y)
{
    draw(x);
    draw(y);
    collide(x, y);
});
Здесь нет PM, и нет общего предка, хотя оба объекта имеют одинаковый интерфейс с точки зрения этой полиморфной лямбды.

G>Имхо, вычисление if-с-else в variant было бы более ценным, если бы была возможность, например, использовать механизмы PM при описании сигнатуры ф-ций. И, соответсвенно, при разрешении их вызовов. Тогда бы, можно было организовать диспетчеризацию не прибегая к явному использованию PM.


Это похоже по описанию на перегрузку функций в C++, там как раз и возможно разруливать ветви variant через перегрузку (а можно и через один шаблон функции, если интерфейс одинаков, как в примере выше).
Re[6]: Что должен возвращать if?
Здравствуйте, gbear, Вы писали:

G>В вашем случае, важна именно полноценная монада maybe. Паллиатив вида variant[T, void] — не даст вам возможности поймать "go wrong".


Почему же не даст? void тут играет роль Nothing.

G>И важен тут, не столько Nothing (который, вполне может быть заменен и на void),


Да, именно.

G>сколько Just. Т.е. если за-предикатное выражение вычисляется в T, то "нормальный" результат вычисления if-без-else будет Just[T], а не T.


Да, и я не вижу в этом проблемы.

G>Если теперь сравнить это с if-с-else, то видно следующее. Чтобы "в качестве результата можно использовать один тип результата" — в вашем случае — его придется вычислять в Just[T], а не в T. Что, вообще говоря, смысла лишено.


Почему же? Для обобщённого кода как раз и не лишено — вне зависимости от того, значения каких типов возвращают ветки if-else, всё выражение вычислится в Variant.
Для обычного, не обобщённого кода, да немного неудобно, но это обходится всего одним унарным оператором/унарной функцией, причём без потери производительности (Variant<T> всегда содержит внутри T, безусловно).
Тут главное не забывать, что if-с-else в общем случае возвращает Variant<T, U>, а не просто Variant<T>, который является всего лишь частным случаем.

G>Даже если "обернуть" все это в variant — это мало что изменит . Типы A и Some[A] — это таки разные типы.

G>Можно потытаться "стереть границы" введя функторы, например... и вот тогда про "два синтаксиса" вообще никто вспоминать уж точно не будет

В случае когда у нас Variant<T>, полноценный функторный fmap не нужен, точнее можно без него. Достаточно T unbox(Variant<T> x);, или короткого оператора.

G>Смотрите, я выше высказался за разрешение неоднозначности при вычислении if-без-else. Действительно её можно снять вычисляя его в maybe. Проблема только в том, что это никакого отношения к вычислению if-с-else не имеет


Maybe действительно не имеет отношения, а вот Varaint — вполне.

G>Добиться "одинаковости" можно лишь вычислением и if-с-else тоже в maybe. Что весьма странно, согласитесь. Ведь никаких неоднозначностей при его вычмслении у нас нет. И никакие variant[A, B] и т.п. не дадут вам взаимозаменяемости, если хотите, между результатами вычислений if-с-else и if-без-else.


Почему же не дадут?

G>Вычисление if-с-else в variant, само по себе (без попытки добиться "симметрии") может иметь смысл. Но только в том случае, когда PM и использование variant уйдут на ступень выше, так сказать.


То есть основная проблема заключается в каких-то пробелах в Nemerle с Varaint'ом как таковым, а не в самой идеи if-else -> Variant?

G>Какой смысл в данный момент получать из if (который, на самом деле PM) variant? Для его обработки все равно придется использовать PM. Если же мы можем выделить общий интерфейс (т.е. при дальнейшей обработки обойтись без PM), то и возвращать из if лучше именно этот интерфейс. Что, как я понимаю, сейчас и делается.


Дело в том, что non-member функции также, грубо говоря, относятся к интерфейсу. Объектам необязательно иметь одинаковые-функции члены и общих предков, чтобы их можно было использовать с одинаковым синтаксисом.
Например на C++ можно вот так:
Variant<Widget, Gadget> x, y;
// ...
apply(x, y, [](auto &x, auto &y)
{
    draw(x);
    draw(y);
    collide(x, y);
});
Здесь нет PM, и нет общего предка, хотя оба объекта имеют одинаковый интерфейс с точки зрения этой полиморфной лямбды.

G>Имхо, вычисление if-с-else в variant было бы более ценным, если бы была возможность, например, использовать механизмы PM при описании сигнатуры ф-ций. И, соответсвенно, при разрешении их вызовов. Тогда бы, можно было организовать диспетчеризацию не прибегая к явному использованию PM.


Это похоже по описанию на перегрузку функций в C++, там как раз и возможно разруливать ветви variant через перегрузку (а можно и через один шаблон функции, если интерфейс одинаков, как в примере выше).