Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 14.01.22 09:38
Оценка:
using System.Diagnostics;
using static System.Console;
using static LanguageExt.Prelude;
Try(() => { WriteLine("DONE");return true;}).Match(_ => WriteLine("OK"), exn => WriteLine(exn));

Чтобы замыкание выполнилось нужно чтобы оно возвращало значение, т.е. либо обернуть в act(()=>{}) либо вернуть что то из метода
иначе метод не будет вызван, но Match отработает, т.е. будет казаться что все работает.
Это еще раз показывает как много в компиляторе C# косяков.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Try из библиотеки LanguageExt.Core
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.01.22 10:07
Оценка:
Здравствуйте, vaa, Вы писали:


vaa>
vaa>using System.Diagnostics;
vaa>using static System.Console;
vaa>using static LanguageExt.Prelude;
vaa>Try(() => { WriteLine("DONE");return true;}).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
vaa>

vaa>Чтобы замыкание выполнилось нужно чтобы оно возвращало значение, т.е. либо обернуть в act(()=>{}) либо вернуть что то из метода
vaa>иначе метод не будет вызван, но Match отработает, т.е. будет казаться что все работает.
vaa>Это еще раз показывает как много в компиляторе C# косяков.

https://louthy.github.io/language-ext/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/index.html#TryExtensions_0_Match_2
method Unit Match <A> (this Try<A> self, Action<A> Succ, Action<Exception> Fail)


Кстати а какой должен будет тип для void?
Try(() => { WriteLine("DONE");}).Match( a => {a.GetType(); WriteLine("OK")}, exn => WriteLine(exn));


Unit?

Может это подойдет
https://stackoverflow.com/questions/13928963/implement-f-interface-member-with-unit-return-type-in-c-sharp
и солнце б утром не вставало, когда бы не было меня
Отредактировано 14.01.2022 11:17 Serginio1 . Предыдущая версия . Еще …
Отредактировано 14.01.2022 10:09 Serginio1 . Предыдущая версия .
Re: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 14.01.22 10:53
Оценка: +6
Здравствуйте, vaa, Вы писали:


vaa>
vaa>using System.Diagnostics;
vaa>using static System.Console;
vaa>using static LanguageExt.Prelude;
vaa>Try(() => { WriteLine("DONE");return true;}).Match(_ => WriteLine("OK"), exn => WriteLine(exn));
vaa>

vaa>Чтобы замыкание выполнилось нужно чтобы оно возвращало значение, т.е. либо обернуть в act(()=>{}) либо вернуть что то из метода
О каком именно замыкании речь? В вышеприведенном коде я ни одного замыкания не вижу.

vaa>иначе метод не будет вызван, но Match отработает, т.е. будет казаться что все работает.

vaa>Это еще раз показывает как много в компиляторе C# косяков.
В чем именно претензии к компилятору C#? Есть какое-то расхождение его поведения со спецификацией языка? Мне кажется, что компилятор C# не в ответе за реализацию данного Match-а.
Re[2]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 17.01.22 02:06
Оценка: 9 (1)
Здравствуйте, Serginio1, Вы писали:


S>Кстати а какой должен будет тип для void?

S>
S>Try().Match( a => {a.GetType(); WriteLine("OK")}, exn => WriteLine(exn));
S>


S>Unit?

Да
S>Может это подойдет
S>https://stackoverflow.com/questions/13928963/implement-f-interface-member-with-unit-return-type-in-c-sharp
Ну тут странное решение(тянуть F#)
достаточно использовать fun
    Try(fun(() => { WriteLine("DONE");}))
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 17.01.22 02:32
Оценка:
Здравствуйте, samius, Вы писали:

S>О каком именно замыкании речь? В вышеприведенном коде я ни одного замыкания не вижу.


Как вообще отличить Lambda от Closure в коде?


vaa>>иначе метод не будет вызван, но Match отработает, т.е. будет казаться что все работает.

vaa>>Это еще раз показывает как много в компиляторе C# косяков.
S>В чем именно претензии к компилятору C#? Есть какое-то расхождение его поведения со спецификацией языка? Мне кажется, что компилятор C# не в ответе за реализацию данного Match-а.
Согласен, дело в деталях реализации библиотеки, но проблема также и на уровне языка.
Вот тут хороший пример https://habr.com/ru/post/511534/ (не косяки, а подводные камни )
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.01.22 05:05
Оценка: 1 (1)
Здравствуйте, vaa, Вы писали:

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


vaa>Как вообще отличить Lambda от Closure в коде?

В коде одно является способом записи анонимной функции и с ним (конкретно в C#) ошибиться сложно, т.к. при этом используется практически уникальный синтаксис =>, если не путать его с короткой записью геттера свойства. Замыкание в коде присутствует неявно и подразумевает способ связывания переменных из лексического окружения в первоклассных функциях.
То есть, в коде мы можем обнаружить примеры использования этих концепций как независимо одно без другого, так и вместе два в одном.

S>>В чем именно претензии к компилятору C#? Есть какое-то расхождение его поведения со спецификацией языка? Мне кажется, что компилятор C# не в ответе за реализацию данного Match-а.

vaa>Согласен, дело в деталях реализации библиотеки, но проблема также и на уровне языка.
С самого начала C# проектировался как C-подобная, или даже Java-подобная версия Basic с возможностями Delphi+VCL. Никаких намеков на грядущие функциональные фичи, или хоть какую-то мультипарадигменность. Ни лямбды, ни замыкания, ни параметрический полиморфизм, ни даже система типов не проектировалсь изначально под функциональщину. Все вкорячивалось по месту с грузом обратной совместимости.

Хаскель изначально развивался как чисто функциональный язык со всеми этими штуками, заложенными изначально. При этом, еще и с ленивой стратегией вычислений.

Поэтому, наивно было бы предполагать, что библиотека, написанная для того, что бы сделать C# похожим на хаскель, вела бы себя органично в C# с учетом его исторического развития. Хотел бы я посмотреть, кстати, на библиотеку для Хаскеля, которая делает его подобным C#. Шутка, если что.

vaa>Вот тут хороший пример https://habr.com/ru/post/511534/ (не косяки, а подводные камни )

Опять-таки мы сравниваем язык, который не имел четкого вектора развития и обрастал своими фичами как Инспектор Гаджет девайсами с языком, который изначально был ориентирован быть функциональным (хоть и на императивной базе) с более стройной системой типов(точнее, их записью), с функциональными типами, вычислительными выражениями и т.п.
Т.е. F# концептуально больше был готов к асинхронщине, т.к. имел уже на борту монады и средства по работе с ними. А в C# более традиционным подходом является компиляторная магия, которая из спецсинтаксиса генерирует машины состояний аки с yield-ом. Судя по всему, кто-то собрал асинки сначала на yield генераторах для IEnumerable<T>, а потом уже под него вкорячили спец синтаксис и интегрировали это решение в язык.

а так — да, хорошо глумиться над async void-ом с позиций языка, в котором void изначально был персоной нон-грата.
Re[3]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.01.22 06:11
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Как вообще отличить Lambda от Closure в коде?

Это две ортогональные концепции.
Замыкание использует в теле переменные или аргументы из контекста метода, в котором строится замыкание. Туда же относится явное либо неявное использование this.
Нет такого использования — нет замыкания.
Lambda — это всего лишь синтаксис для записи анонимных методов. Можно делать замыкания без лямбд и лямбды без замыканий.



S>>В чем именно претензии к компилятору C#? Есть какое-то расхождение его поведения со спецификацией языка? Мне кажется, что компилятор C# не в ответе за реализацию данного Match-а.

vaa>Согласен, дело в деталях реализации библиотеки, но проблема также и на уровне языка.
vaa>Вот тут хороший пример https://habr.com/ru/post/511534/ (не косяки, а подводные камни )
Не очень понятно, что имеется в виду. Я не смог найти документацию по методу Try(), который вы используете. Ну, кроме упоминания о том, что монады TryXXX<A> задепрекейчены в пользу Aff<A> и Eff<A>.
И вообще почти вся библиотека постепенно становится бесполезной с выходом новых версий C#.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 17.01.22 06:23
Оценка:
Здравствуйте, samius, Вы писали:

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


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


vaa>>Как вообще отличить Lambda от Closure в коде?

S>В коде одно является способом записи анонимной функции и с ним (конкретно в C#) ошибиться сложно, т.к. при этом используется практически уникальный синтаксис =>, если не путать его с короткой записью геттера свойства. Замыкание в коде присутствует неявно и подразумевает способ связывания переменных из лексического окружения в первоклассных функциях.
S>То есть, в коде мы можем обнаружить примеры использования этих концепций как независимо одно без другого, так и вместе два в одном.

Насколько я понимаю, под связыванием в замыкании подразумевается запоминание значений связываемых переменных на момент определения замыкания,
а лямбда использует текущее на момент вызова значение связанной переменной.
Есть ли пример кода замыкания? т.к. все эксперименты с лямбдами и делегатами работают без замыкания.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.01.22 06:33
Оценка:
Здравствуйте, vaa, Вы писали:
vaa>а лямбда использует текущее на момент вызова значение связанной переменной.
Не значение, а саму переменную.
vaa>Есть ли пример кода замыкания? т.к. все эксперименты с лямбдами и делегатами работают без замыкания.

public static Func<int, int> MakeAdd(int x)
  => (int y) => x + y; 

[Fact]
public void TestAdd()
{
   Assert.Equal(42, MakeAdd(5)(37));
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 17.01.22 06:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


vaa>>Как вообще отличить Lambda от Closure в коде?

S>Это две ортогональные концепции.
S>Замыкание использует в теле переменные или аргументы из контекста метода, в котором строится замыкание. Туда же относится явное либо неявное использование this.
S>Нет такого использования — нет замыкания.
S>Lambda — это всего лишь синтаксис для записи анонимных методов. Можно делать замыкания без лямбд и лямбды без замыканий.

Не обязательно
(setq a 10)
(setq f1 (lambda (b)
       (+ a b))) ;; (setq lexical-binding nil) даст (lambda (b) (+ a b))
;; (setq lexical-binding t) даст (closure (t) (b) (+ a b))
(funcall f1 1)

(let ((a 20))
  (funcall f1 1))
;; в первом случае 11 21
;; во втором случае 11 11


В C# не пойму как реализовать

S>>>В чем именно претензии к компилятору C#? Есть какое-то расхождение его поведения со спецификацией языка? Мне кажется, что компилятор C# не в ответе за реализацию данного Match-а.

vaa>>Согласен, дело в деталях реализации библиотеки, но проблема также и на уровне языка.
vaa>>Вот тут хороший пример https://habr.com/ru/post/511534/ (не косяки, а подводные камни )
S>Не очень понятно, что имеется в виду. Я не смог найти документацию по методу Try(), который вы используете. Ну, кроме упоминания о том, что монады TryXXX<A> задепрекейчены в пользу Aff<A> и Eff<A>.
не оно?
https://louthy.github.io/language-ext/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/index.html#LanguageExt_0_Try_1
S>И вообще почти вся библиотека постепенно становится бесполезной с выходом новых версий C#.
Можете привести пример для данного случая?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.01.22 06:48
Оценка:
Здравствуйте, vaa, Вы писали:


vaa>Не обязательно

vaa>
vaa>;(setq a 10)
vaa>;(setq f1 (lambda (b)
vaa>;       (+ a b))) ;; (setq lexical-binding nil) даст (lambda (b) (+ a b))
vaa>;;; (setq lexical-binding t) даст (closure (t) (b) (+ a b))
vaa>;(funcall f1 1)

vaa>;(let ((a 20))
vaa>;  (funcall f1 1))
vaa>;;; в первом случае 11 21
vaa>;;; во втором случае 11 11
vaa>;


vaa>не оно?

Оно, но по прежнему непонятно, что такое Try. Вот это вот — что за булшит?

delegate Try <A>

Синтаксис объявления делегатов в C# включает в себя типы аргументов и возвращаемого значения. Здесь нет ни того, ни другого — какая-то неведомая хтонь. Вообще вся дока написана на каком-то воображаемом языке.

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

S>>И вообще почти вся библиотека постепенно становится бесполезной с выходом новых версий C#.
vaa>Можете привести пример для данного случая?

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

А про бесполезность библиотеки я имел в виду не столько монадическую часть, сколько все вот эти Record, RecordType, инициализаторы иммутабл коллекций, а также Option<T>.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 17.01.22 07:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Оно, но по прежнему непонятно, что такое Try. Вот это вот — что за булшит?

https://github.com/louthy/language-ext/blob/101937cf4d634da86866fa2a9b9df599990ffea5/LanguageExt.Core/Monads/Alternative%20Value%20Monads/Try/Try/Try.cs#L13
Да, видимо генератор доков сломался
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.01.22 08:04
Оценка:
Здравствуйте, vaa, Вы писали:

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


vaa>>>Как вообще отличить Lambda от Closure в коде?

S>>В коде одно является способом записи анонимной функции и с ним (конкретно в C#) ошибиться сложно, т.к. при этом используется практически уникальный синтаксис =>, если не путать его с короткой записью геттера свойства. Замыкание в коде присутствует неявно и подразумевает способ связывания переменных из лексического окружения в первоклассных функциях.
S>>То есть, в коде мы можем обнаружить примеры использования этих концепций как независимо одно без другого, так и вместе два в одном.

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

нет, речь именно о переменной с возможностью изменять ее значение.
vaa>а лямбда использует текущее на момент вызова значение связанной переменной.
разумеется. Но лямбда в C# — это лишь еще одна форма записи того, что можно записать по-другому. С помощью delegate, например. Или с недавних пор с помощью локальной функции.

vaa>Есть ли пример кода замыкания? т.к. все эксперименты с лямбдами и делегатами работают без замыкания.

Не понимаю, что значит пример кода замыкания. Замыкание — это техника, лежащая под капотом компилятора. Код может лишь указывать на то, что для исполнения его потребуется выполнить замыкание. Для того, что бы посмотреть, что выходит, можно воспользоваться декомпилятором.

Ниже пример того, что в замыкании участвует именно общая переменная, а не значение на момент определения замыкания.
void Main()
{
    var foo = Foo();
    var inc1 = foo();
    var inc2 = foo();
    
    inc1().Dump(); // 1
    inc2().Dump(); // 2
}

Func<Func<int>> Foo()
{
    int i = 0;
    return () => () => ++i;
}
Re[7]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.01.22 08:20
Оценка:
Здравствуйте, vaa, Вы писали:
vaa>Да, видимо генератор доков сломался
Там не в генераторе доков дело.
Я вроде понял в чём дело, но надо руками пощупать эту библиотеку.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.01.22 09:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

vaa>>Да, видимо генератор доков сломался
S>Там не в генераторе доков дело.
S>Я вроде понял в чём дело, но надо руками пощупать эту библиотеку.
Да, посмотрел. Я так и думал. Проблема не в компиляторе, а в библиотеке, которая работает неожиданным для вас образом.
Компилятор работает корректно.
Присланная вами ссылка на проблемы async void методов тоже никакого отношения к проблемам приведённого вами сниппета не имеет.
Дизайн языка, в целом, тоже норм.

А вот разработчик библиотеки поленился написать код для идиоматической интеграции библиотеки в язык.
В чём тут проблема? В том, что у Prelude.Try есть две сигнатуры. Автор имел в виду, что "одна сигнатура будет покрывать функции, а другая — значения".
Но у нас же не вырожденный ФП-язык, где у любой функции 1 аргумент и 1 результат. А нормальный, современный язык программирования, в котором функция является объектом первого класса и поддерживает различное количество аргументов, и некоторое разнообразие в возвращаемых результатах.
Смотрите за руками:
Try((int x) => { WriteLine("DONE"); return x; }).Match(_ => WriteLine("OK"), exn => WriteLine(exn));

Возвращаемое значение — есть, а Match по-прежнему не работает!
А всё потому, что "функциональная" перегрузка Try ловит ровно одну сигнатуру фунций — Func<A>. А все остальные сигнатуры сваливаются в перегрузку Try<A>(A value).
И вообще, весь тип Try<A> — одно сплошное горе, обнять и плакать.

Для того, чтобы заменить выброс исключений на возврат альтернативных значений, нужно сделать столько же типов Try, сколько есть Func<...> и Action<...> типов.
И, соответственно, наплодить нужное количество перегрузок в Prelude.Try.
Ведь нужные вам перегрузки выглядят вот так:
public Result delegate Try(); // non-generic Result behaves as non-generic Task: it either captures nothing or an exception thrown from action
public static class Prelude
{
  public static Try Try(Action a)
    => ()=>  { try {a(); return Result.Success;} 
               catch(Exception e) { return Result.FromException(e);
  }
}

public static class TryExtenions
{
  public static void Match(this Try ma; Action succ; Action<Exception> Fail)
  {
    var res = self.Try();
    if (res.IsFaulted)
      Fail(res.Exception);
    else
      Succ();
  }
}

Заодно это убрало бы у вас дискард — который всё равно ничему не может быть равен, т.к. ваша WriteLine("DONE") ничего не возвращает.
А для того, чтобы заработал приведённый мной код, потребуются вот такие вот перегрузки:
public Result<A> delegate Try<T, A>(T t); 
public static class Prelude
{
  public static Try<T, A> Try<T, A>(Func<T, A> f) => (T x) => f(x);
}

public static class TryExtenions
{
  public static Func<T, R> Match<T, A, R>(this Try<T, A> ma; Func<A, R> succ; Func<Exception, R> fail)
    => (T x) => 
       {
      var res = self.Try(x); 
          return res.IsBottom ? Fail(res.Exception ?? new BottomException())
                : res.IsFaulted ? Fail(res.Exception)
                : Succ(res.Value);  
       }
}

Ну, то есть на самом деле надо копать — тут не очень понятно, как смешиваются функции, возвращающие Result<A>, с функциями, возвращающими просто A. У автора библиотеки с этим некоторый бардак — в частности, если один из параметров succ или fail сам выбросит исключение, оно неожиданным образом вылетит из Match, напугав автора кода — ведь он-то ожидал как раз избавления от исключений!
В общем, эта часть библиотеки выглядит сыро.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 17.01.22 13:10
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

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


Есть версия, что это попытка воспроизвести Railway oriented programming (https://fsharpforfunandprofit.com/rop/)
т.е. Result — монадический тип аки Option<T>/Either для записи цепочки вычислений в виде монад.

S>В общем, эта часть библиотеки выглядит сыро.

А с учетом аспектов, изложенных вот тут (https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/), оно еще и не выглядит полезным.
Re[6]: Try из библиотеки LanguageExt.Core
От: vaa  
Дата: 18.01.22 01:43
Оценка:
Здравствуйте, samius, Вы писали:

S>Ниже пример того, что в замыкании участвует именно общая переменная, а не значение на момент определения замыкания.

да, тупанул, действительно сложнее реализовать именно поведение лямбды
using static System.Console;
var x = 42;
Action<int> closure = a => { WriteLine("closure = {0}", a + x); };
Action<int> lambda = Lambda(x);
closure(5);
lambda(5);
x = 11;
closure(5);
lambda(5);

Action<int> Lambda(int a) =>
    x => { WriteLine("lambda = {0}", x + a); };

что в ILSpy выглядит
using System;

private static void <Main>$(string[] args)
{
    int x2 = 42;
    Action<int> closure = delegate(int a)
    {
        Console.WriteLine("closure = {0}", a + x2);
    };
    Action<int> lambda = Lambda(x2);
    closure(5);
    lambda(5);
    x2 = 11;
    closure(5);
    lambda(5);
    static Action<int> Lambda(int a)
    {
        return delegate(int x)
        {
            Console.WriteLine("lambda = {0}", x + a);
        };
    }
}


closure = 47
lambda = 47
closure = 16
lambda = 47


Получается через лямбда-синтаксис выразить лямбду невозможно?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 18.01.2022 2:03 Разраб . Предыдущая версия .
Re[10]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.01.22 02:17
Оценка:
Здравствуйте, samius, Вы писали:

S>Есть версия, что это попытка воспроизвести Railway oriented programming (https://fsharpforfunandprofit.com/rop/)

S>т.е. Result — монадический тип аки Option<T>/Either для записи цепочки вычислений в виде монад.
Да, это именно так.

S>>В общем, эта часть библиотеки выглядит сыро.

S>А с учетом аспектов, изложенных вот тут (https://fsharpforfunandprofit.com/posts/against-railway-oriented-programming/), оно еще и не выглядит полезным.
Ага, согласен.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Try из библиотеки LanguageExt.Core
От: samius Япония http://sams-tricks.blogspot.com
Дата: 18.01.22 02:21
Оценка: 24 (2)
Здравствуйте, vaa, Вы писали:

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


S>>Ниже пример того, что в замыкании участвует именно общая переменная, а не значение на момент определения замыкания.

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

vaa>Получается через лямбда-синтаксис выразить лямбду невозможно?

Бррр...

В C#, раз речь о нем, лямбдой называется короткий способ записи функции. В базе любую функцию (на самом деле, нет), можно записать в виде лямбда выражения/оператора.
Что нельзя записать — функции, использующие unsafe, передачу параметров по ссылке и что-то еще. Здесь и сейчас это не важно. Для простоты будем считать, что любую.

С лямбдой на этом всё. Это способ записи, причем, мы всегда можем записать функцию по-другому. Например, delegate может описывать функции там же, где и лямбда.
Далее про лямбду можно забыть вовсе, она не интересна. Это просто сахар и только, у сахара нет поведения, которое можно наблюдать. Единственное, что мы можем наблюдать — так это то, что функция, записанная через лямбду, будет вести себя так же,как и функция, записанная делегатом или как-то еще.

Поэтому, выражение "через лямбда-синтаксис выразить лямбду" выгляидит (с точки зрения C#, повторюсь) как "через функцию выразить функцию". Что странно выглядит в одном утверждении со словом "невозможно".

Но если мы говорим о лямбда-исчислении и о том, что не всякую лямбду из лямбда-исчисления можно выразить в C#, то да, это справедливо. Но справедливо слишком, т.к. у нас разные системы типизации. Без конкретики сложно поддерживать беседу.

Далее интересно вот что: использует ли функция лишь свои переменные (локальные, параметры, или поля класса, в котором она определена), либо еще использует переменные, определенные где-то во внешнем лексическом контексте. Например, локальные переменные, которые определены в функции, которая определяла данную функцию в своем теле. Если такие переменные есть, то компилятор задействует технику "замыкание". На уровне кода это синтаксически никак не отражено. Нужно внимательно разобраться с областями видимости задействованных переменных, что бы понять, будет ли задействовано замыкание для использования некоторой переменной. Но это не точно. Компилятор может втащить в замыкание переменные, которые там не нужны.

В последнем параграфе для лямбды не нашлось места вовсе. Все, что справедливо для функций, будет справедливо и для лямбд (в рамках C#).
Re[7]: Try из библиотеки LanguageExt.Core
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.01.22 02:25
Оценка: 9 (1)
Здравствуйте, vaa, Вы писали:

vaa>Получается через лямбда-синтаксис выразить лямбду невозможно?


Вы "лямбдой" называете замыкание значения, а не ссылки? Тогда да, надо использовать синтаксис анонимных делегатов.
Примерно так:
using System;
using static System.Console;
var x = 42;
Action<int> closure = a => { WriteLine("closure = {0}", a + x); };
Func<Action<int>> lambda = ()=>{var y=x; return (a)=> WriteLine("lambda = {0}", a + y); };
closure(5);
lambda()(5);
x = 11;
closure(5);
lambda()(5);
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.