Re[9]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 18.01.22 02:37
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Смотрите за руками:
S>
S>Try((int x) => { WriteLine("DONE"); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>

S>Возвращаемое значение — есть, а Match по-прежнему не работает!

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

using LanguageExt;
using static System.Console;
using static LanguageExt.Prelude;

string message = "Done";
PrintMessage(message).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
//что эквивалентно, благодоря fun
Try(fun(() => WriteLine(message))).Match(_ => WriteLine("OK"), exn => WriteLine(exn));

Try<Unit> PrintMessage(string message)
{
    return () =>
    {
        WriteLine(message);
        return unit;
    };
}


S>Ну, то есть на самом деле надо копать — тут не очень понятно, как смешиваются функции, возвращающие Result<A>, с функциями, возвращающими просто A. У автора библиотеки с этим некоторый бардак — в частности, если один из параметров succ или fail сам выбросит исключение, оно неожиданным образом вылетит из Match, напугав автора кода — ведь он-то ожидал как раз избавления от исключений!

Вот это не понял, если ваш код может бросить исключение что в этом пугающего? Очевидно, что мы ограждаемся от исключений только в вызове Try<A>.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[10]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.01.22 08:09
Оценка: 2 (1)
Здравствуйте, vaa, Вы писали:

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

S>>Смотрите за руками:
S>>
S>>Try((int x) => { WriteLine("DONE"); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>>

S>>Возвращаемое значение — есть, а Match по-прежнему не работает!

vaa>Да тут есть определенный косяк, что нужно учитывать императивное мышление шапристов

Императивное мышление шарпистов тут ни при чём.

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

Естественно. Код выполняется во всех случаях .

using LanguageExt;
using static System.Console;
using static LanguageExt.Prelude;

string message = "Done";
PrintMessage(message).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
//что эквивалентно, благодоря fun
Try(fun(() => WriteLine(message))).Match(_ => WriteLine("OK"), exn => WriteLine(exn));

Try<Unit> PrintMessage(string message)
{
    return () =>
    {
        WriteLine(message);
        return unit;
    };
}

Ну, всё верно. Здесь вы вручную утаптываете ваш код в ту самую сигнатуру Func<A> — безаргументной функции, возвращающей одно значение.
Это по-прежнему никак не помогает нам обработать случай с функцией int->int.

S>>Ну, то есть на самом деле надо копать — тут не очень понятно, как смешиваются функции, возвращающие Result<A>, с функциями, возвращающими просто A. У автора библиотеки с этим некоторый бардак — в частности, если один из параметров succ или fail сам выбросит исключение, оно неожиданным образом вылетит из Match, напугав автора кода — ведь он-то ожидал как раз избавления от исключений!

vaa>Вот это не понял, если ваш код может бросить исключение что в этом пугающего? Очевидно, что мы ограждаемся от исключений только в вызове Try<A>.
Смысл не в том, чтобы "оградиться от исключений в каком-то коде". Идея railway programming — в том, что вместо исключений мы используем варианты возврата.
Для того, чтобы она работала (хотя бы в том ограниченном смысле, как она может вообще работать), её обработчиками в match должны тоже быть не плоские функции, а соответствующие Try-монады.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Try из библиотеки LanguageExt.Core
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.01.22 09:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Для того, чтобы она работала (хотя бы в том ограниченном смысле, как она может вообще работать), её обработчиками в match должны тоже быть не плоские функции, а соответствующие Try-монады.


Ну в F# Каррирование упрощает работу https://lsreg.ru/shpargalka-po-f/
и солнце б утром не вставало, когда бы не было меня
Re[12]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.01.22 12:09
Оценка: 9 (1)
Здравствуйте, Serginio1, Вы писали:
S> Ну в F# Каррирование упрощает работу https://lsreg.ru/shpargalka-po-f/
Это не в F#, это вообще удивительный мир ФП, где других функций, в общем-то, и нету.
Основное преимущество такого подхода — концептуальная чистота.
Основной недостаток — это отсутствие внятного автодополнения и нормальных перегрузок по типам аргументов.
Отдельным бонусом идёт чудовищная неэффективность — АФАИК, порождение эффективного кода для функций в таком стиле несовместимо с CLR.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 19.01.22 03:01
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>>>
S>>>Try((int x) => { WriteLine("DONE"); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>>>

S>>>Возвращаемое значение — есть, а Match по-прежнему не работает!
S>Это по-прежнему никак не помогает нам обработать случай с функцией int->int.

Вот вообще непонятно кто так станет делать?
В вашем случае Try возвращает Func<int,int>. И(следите за руками) Match по-прежнему работает!
Но да согласен с появлением нормальных record в C# быть может данный кейс уже не так актуален.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[12]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.01.22 04:09
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Вот вообще непонятно кто так станет делать?

В каком смысле? Сигнатуры функций бывают различными. Вовсе не обязательно функция должна иметь 0 параметров.
vaa>В вашем случае Try возвращает Func<int,int>. И(следите за руками) Match по-прежнему работает!
Нет конечно, ничего не работает. WriteLine("DONE") не выполняется; аргумент Fail при исключении тоже не выполнится:
Try((int x) => { WriteLine("DONE"); throw new InvalidOperationException(); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));

vaa>Но да согласен с появлением нормальных record в C# быть может данный кейс уже не так актуален.
Рекорды тут ни при чём.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 19.01.22 04:37
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Нет конечно, ничего не работает. WriteLine("DONE") не выполняется; аргумент Fail при исключении тоже не выполнится:

S>
S>Try((int x) => { WriteLine("DONE"); throw new InvalidOperationException(); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>

И откуда возьмется x чтобы лямбда посчиталась? результат работы try функция а не ее результат. хм... матч то тут причем?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[14]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.01.22 05:15
Оценка: +1
Здравствуйте, vaa, Вы писали:

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


S>>Нет конечно, ничего не работает. WriteLine("DONE") не выполняется; аргумент Fail при исключении тоже не выполнится:

S>>
S>>Try((int x) => { WriteLine("DONE"); throw new InvalidOperationException(); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>>

vaa>И откуда возьмется x чтобы лямбда посчиталась? результат работы try функция а не ее результат. хм... матч то тут причем?
Здесь нет кода, вызывающего лямбду. Матч выполняет Try над первым аргументом, результатом будет вот эта лямбда, которая записана в Try. Матч должен выполнить либо первый, либо второй экшн и вернуть Unit.
Где-то в консоли должен быть ОК, тело лямбды никто не выполняет, исключение в нем не возбуждается. (Код не запускал, если что).
Re[14]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.01.22 05:23
Оценка: 6 (2)
Здравствуйте, vaa, Вы писали:
S>>Нет конечно, ничего не работает. WriteLine("DONE") не выполняется; аргумент Fail при исключении тоже не выполнится:
S>>
S>>Try((int x) => { WriteLine("DONE"); throw new InvalidOperationException(); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
S>>

vaa>И откуда возьмется x чтобы лямбда посчиталась? результат работы try функция а не ее результат. хм... матч то тут причем?
Всё верно.
Чего мы ожидаем от конструкции Try().Match()?
Что она превратит некую функцию, бросающую исключения, в функцию, которая исключений не бросает, а выполняет действия, указанные в match.
Результатом указанного кода должна стать Action<int>, которая при вызове на любом аргументе выводит "InvalidOperationException".
А в реальности результатом будет Unit. Увы.

Я вижу, вам сложно воспринимать код C#.
Давайте я напишу помедленнее.
Начнём с двух простых методов.
Func<int, int> foo = x => x % 2 == 0 ? 1 : throw new Exception("Oops");
Func<int> bar = () => foo(DateTime.Now.Millisecond);

Первый из них отображает int->int, и иногда бросает исключение.
Второй — всего лишь обёртка над первым, которая в качестве параметра использует текущее значение времени.

Давайте теперь попробуем посмотреть, что можно с ними сделать с помощью Try.
Начнём со второго:
// 1. Working with the parameterless function:
// 1.1. Wrapping into the Try monad:
var tryBar = Try(bar);
// 1.2 Direct execution (note the lack of params in Try):
var barResult = tryBar.Try(); // Result<int>
// 1.3. Coalescing exceptions into default value
var barFinalResult = barResult.Match(x => x, ex => 1);
Assert.Equal(1, barFinalResult);
// 1.4. Shortcut coalescing:
barFinalResult = tryBar.Match(x => x, ex => 1);
Assert.Equal(1, barFinalResult);
// 1.5. Returnless matching:
tryBar.Match(x => WriteLine(x), ex => WriteLine(ex));

удобная вроде штука — мы превратили Func<int> throws Exception сначала в Func<Result<int>>, затем просто в Result<int>, а потом и в просто int.
Ну, или если нам результат функции нужен был просто в рамках некоего побочного эффекта (вывод на экран), то мы это сделали в одну строку в 1.5.


Попробуем сделать что-то похожее с foo:
var tryFoo = Try(foo);

Логично ожидать аналогичного поведения — наверное, у tryFoo будет доступен метод Try(int), который тоже вернёт Result<int>, чтобы по нему можно было матчиться.
А методы Match должны принимать int в качестве дополнительного параметра.
Ну, то есть мне логичным видится делать даже не это, а строить обратно Func<int, int> либо Action<int>, в зависимости от сигнатур переданных в Match обработчиков.
Но это бы означало ленивость Match, что противоречит поведению того убогого Match, который реализован в этой библиотеке для функций в стиле bar.

Но нет! у tryFoo есть только один метод Try, у которого нет параметров. И возвращает он вовсе не Result<int>, а Result<Func<int, int>>, который полностью бесполезен для наших целей.
Мы, конечно, можем выковырять этот Func<int, int> из Result, но даже после Match он продолжает сыпать исключениями.
Никаким способом мы из tryFoo не можем получить ожидаемое — Func<int, int>, которая для любого аргумента вернёт 1.
Поэтому здравомыслие автора библиотеки вызывает вопросы.

Если что-то непонятно, спрашивайте.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 19.01.2022 5:31 Sinclair . Предыдущая версия .
Re: Try из библиотеки LanguageExt.Core
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.01.22 07:54
Оценка:
Здравствуйте, vaa, Вы писали:


https://louthy.github.io/language-ext/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/index.html#TryExtensions_0_Match_2

method R Match <A, R> (this Try<A> self, Func<A, R> Succ, Func<Exception, R> Fail)


Я думаю, что проблема в Try<A>
А должно быть
Try<Func<A>>, Try<Action>
и солнце б утром не вставало, когда бы не было меня
Re[2]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 19.01.22 08:44
Оценка:
Здравствуйте, Serginio1, Вы писали:

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



S>https://louthy.github.io/language-ext/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/index.html#TryExtensions_0_Match_2


S>
S>method R Match <A, R> (this Try<A> self, Func<A, R> Succ, Func<Exception, R> Fail)
S>


S>Я думаю, что проблема в Try<A>

S>А должно быть
S>
S>Try<Func<A>>, Try<Action>
S>

Собственно функция-конструктор Try<A> и возвращает функцию A.
Возможно нужно было Try<T> назвать по другому, например Do<T>
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Try из библиотеки LanguageExt.Core
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.01.22 09:53
Оценка:
Здравствуйте, vaa, Вы писали:


vaa>Собственно функция-конструктор Try<A> и возвращает функцию A.

vaa>Возможно нужно было Try<T> назвать по другому, например Do<T>
Я к тому, что ошибка должна быть на этапе компиляции
Try((int x) => { WriteLine("DONE"); return x; })
и солнце б утром не вставало, когда бы не было меня
Re[4]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.01.22 10:25
Оценка: 18 (1) +1
Здравствуйте, Serginio1, Вы писали:

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



vaa>>Собственно функция-конструктор Try<A> и возвращает функцию A.

vaa>>Возможно нужно было Try<T> назвать по другому, например Do<T>
S> Я к тому, что ошибка должна быть на этапе компиляции
S>
S>Try((int x) => { WriteLine("DONE"); return x; })
S>

За счет чего?
https://github.com/louthy/language-ext/blob/main/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/Try.Prelude.cs#L28
Метод Try<A> принимает в качестве значения типа A функцию Func<int,int> и возвращает делегат, возвращающий это значение-функцию Func<int,int>.
Re[5]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.01.22 11:28
Оценка:
Здравствуйте, samius, Вы писали:
S>Метод Try<A> принимает в качестве значения типа A функцию Func<int,int> и возвращает делегат, возвращающий это значение-функцию Func<int,int>.
Можно попробовать убрать нафиг этот метод, т.к. непонятно, насколько он нужен. Пока что выглядит так, что он кроме граблей никакой пользы не приносит — но для полного понимания хотелось бы, конечно, примеров кода на этой библиотеке.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.01.22 11:56
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

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

S>>Метод Try<A> принимает в качестве значения типа A функцию Func<int,int> и возвращает делегат, возвращающий это значение-функцию Func<int,int>.
S>Можно попробовать убрать нафиг этот метод, т.к. непонятно, насколько он нужен. Пока что выглядит так, что он кроме граблей никакой пользы не приносит — но для полного понимания хотелось бы, конечно, примеров кода на этой библиотеке.
Что бы понять, насколько этот метод нужен, нужно понять, что мы делаем, и как будет выглядеть код без использования этого метода.
Есть такое ощущение, что мы пытаемся найти обстоятельства, в которых эта библиотека делает что-то интуитивно понятное, но неизвестно заранее, что именно. Но да, с помощью этой библиотеки слишком легко сделать из чего угодно Unit/void, не прибегая к усилиям, и даже не пытаясь вычислить что-нибудь. Но нужна ли такая библиотека для этого? C# и сам с этим справится на раз.
Re[15]: Try из библиотеки LanguageExt.Core
От: maxkar  
Дата: 19.01.22 21:27
Оценка: 116 (4) +1
Здравствуйте, Sinclair, Вы писали:

S>Чего мы ожидаем от конструкции Try().Match()?

S>Что она превратит некую функцию, бросающую исключения, в функцию, которая исключений не бросает, а выполняет действия, указанные в match.

А с чего это? Вообще, конечно, библиотека укуренная. В ней два момента. Во-первых, судя по наличию TryExtensions.Retry, это ленивое вычисление (наверное, более правильный термин — по требованию/on demand), которое форсируется (выполняется) вызовом определенных методов. Match и Try — это два из нескольких форсирующих методов. Во-вторых, если не смотреть на ленивость, Try это практически аналог Result. Отличие только в обработке исключений в Map. Result.Map(x => throw Exception("Today is a bad day")) выбросит исключение (наверное..., я в данной библиотеке ничего не гарантирую). А вот Try.Map(x => throw Exception("Today is a bad day")) вычислит TryFail(Exception("Today is a bad day")).

Вообще авторы молодцы — сделали три совершенно противоположных друг другу перегрузки. Try<A>(Exception e) == TryFail(e), Try<A>(A a) == TrySucc(a) и наконец правильный конструктор Try<A>(Func<A> a). Условно,

using Try<A> = Func<Result<A>>

method Try<A>(Exception e): Func<Result<A>> {
  return () => ResultFail(e);
}
method Try<A>(A a): Func<Result<A>> {
  return () => ResultSuccess(e);
}
method Try<A>(Func<A> fn): Func<Result<A>> {
  return () => {
    try {
      ResultSuccess(fn()) // close to TrySucc
    } catch(Exception e) {
      ResultFail(e) // close to TryFail
    }
  }
}

method R Match <A, R> (this Try<A> self, Func<A, R> Succ, Func<Exception, R> Fail) {
  // force computation
  val resultValue: Result<A> = self()
  // and process outcomes, same as resultValue.Match(Succ, Fail)
  if (resultValue.isSuccess()) {
    return Succ(resultValue.value);
  } else {
    return Fail(resultValue.exception);
  }
}

method A Try<A>(this Try<A> self) {
  return self();
}


Можно для чистоты сделать Try<A> оберткой над Fun<Result<A>>, добавится грязи в виде распаковки/запаковки но принципиально ничего не изменит.

S>Попробуем сделать что-то похожее с foo:

S>Логично ожидать аналогичного поведения — наверное, у tryFoo будет доступен метод Try(int), который тоже вернёт Result<int>, чтобы по нему можно было матчиться.

Ожидать — логично. Но перегрузки Try<A>(A) и Try<A>(Exception) не должны были бы существовать вообще, чтобы избежать данной проблемы.

S>А методы Match должны принимать int в качестве дополнительного параметра.

S>Ну, то есть мне логичным видится делать даже не это, а строить обратно Func<int, int> либо Action<int>, в зависимости от сигнатур переданных в Match обработчиков.
S>Но это бы означало ленивость Match, что противоречит поведению того убогого Match, который реализован в этой библиотеке для функций в стиле bar.

Я понимаю, откуда растут ожидания. Но, к сожалению, нет. Try — это ленивое вычисление значения. Если бы пришлось писать TrySucc(foo) непоняток было бы гораздо меньше.

S>Но нет! у tryFoo есть только один метод Try, у которого нет параметров. И возвращает он вовсе не Result<int>, а Result<Func<int, int>>, который полностью бесполезен для наших целей.

S>Мы, конечно, можем выковырять этот Func<int, int> из Result, но даже после Match он продолжает сыпать исключениями.
S>Никаким способом мы из tryFoo не можем получить ожидаемое — Func<int, int>, которая для любого аргумента вернёт 1.

Почему никаким? Это же обычный "хитрый функтор":
var tryFoo = Try(foo);
var appliedFoo = tryFoo.Map(fn => fn(DateTime.Now.Millisecond))
appliedFoo.Match(x => x, ex => 1)

Для такого просится extension method на Try<Funс<A, B>>, но в данную библиотеку его не положили. Ну и название метода Try тоже за гранью добра и зла. Execute/Evaluate/ToResult/Perform — лучше бы передавало семантику. ToResult был бы ближе всего, если бы не было on demand вычислений. Или бы не делали кучу "удобств" и заставляли писать вручную Try().Match(...). Может тоже было бы понятней.

S>Поэтому здравомыслие автора библиотеки вызывает вопросы.


В плане применимости — жить можно. Это же монада. Потому и нужно с ней работать, как с монадой — Map/Bind/Apply. А вот всякие extractors — только в конце вычислений. Но без for comprehension/do notation это все очень не практично.

S>Если что-то непонятно, спрашивайте.


Аналогично. Если что не понятно про монады — спрашивайте (на шарпе я не очень пишу ). В качестве упражнения всем интересующимся рекомендую написать базовые методы Map и Bind на основе определения Try как алиаса типа.
Re[4]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 20.01.22 01:33
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Я к тому, что ошибка должна быть на этапе компиляции

S>
S>Try((int x) => { WriteLine("DONE"); return x; })
S>


Почему? Разве функции не первоклассные сущности? Try это контейнер который может хранить все что вам захочется.
Иначе композировать не получится.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[16]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.01.22 02:28
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Ожидать — логично. Но перегрузки Try<A>(A) и Try<A>(Exception) не должны были бы существовать вообще, чтобы избежать данной проблемы.



Так уже все встает на свои места
Re[5]: Try из библиотеки LanguageExt.Core
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.01.22 08:26
Оценка:
Здравствуйте, vaa, Вы писали:

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


S>> Я к тому, что ошибка должна быть на этапе компиляции

S>>
S>>Try((int x) => { WriteLine("DONE"); return x; })
S>>


vaa>Почему? Разве функции не первоклассные сущности? Try это контейнер который может хранить все что вам захочется.

vaa>Иначе композировать не получится.
Ну с точки зрения ФП все является функцией, а вот в ИП нет. Там я так понял, что есть импликит A к Try<A>
[Pure]
        public static Try<A> Try<A>(A v) =>
            () => v;


Что такое Try<A> я так и не нашел
https://github.com/louthy/language-ext/blob/main/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/Try.Prelude.cs#L28

Понравился ответ
http://rsdn.org/forum/dotnet/8175660.1
Автор: maxkar
Дата: 20.01.22
и солнце б утром не вставало, когда бы не было меня
Re[6]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 20.01.22 08:59
Оценка: 9 (1)
Здравствуйте, Serginio1, Вы писали:


S>Что такое Try<A> я так и не нашел


https://github.com/louthy/language-ext/blob/101937cf4d634da86866fa2a9b9df599990ffea5/LanguageExt.Core/Common/Result/Result.cs#L39
☭ ✊ В мире нет ничего, кроме движущейся материи.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.