CSharpFunctionalExtensions

3

Ludzie tu pisali, że language-ext za trudne, nikt tego nie będzie używał, po co to komu itd. No to może: https://github.com/vkhorikov/CSharpFunctionalExtensions w zamian? :) Za radą @somekind każdy sobie pisze jakieś Resulty zamiast spamować wyjątkami, więc czemu by nie użyć gotowego rozwiązania, które w dodatku sporo oferuje i jest jednocześnie proste w obsłudze? Taki przykład z Readme:

return _customerRepository.GetById(id)
    .ToResult("Customer with such Id is not found: " + id)
    .Ensure(customer => customer.CanBePromoted(), "The customer has the highest status possible")
    .Tap(customer => customer.Promote())
    .Tap(customer => _emailGateway.SendPromotionNotification(customer.PrimaryEmail, customer.Status))
    .Finally(result => result.IsSuccess ? Ok() : Error(result.Error));
0

Jaki masz problem? Co używać ?

0

Ludzie tu pisali, że language-ext za trudne, nikt tego nie będzie używał, po co to komu itd.

że to?

int x = optional
	    .Some( v  => v * 2 )
	    .None( () => 0 );

yaay

int x = optional * 2 ?? 0; // actually nullable
0

Podoba mi się to That's good because we are using the compiler to our advantage.

ale takie rzeczy

Console.WriteLine(movie.Map(m => m.Title.ToUpper(), () => "No movie found"));

czy

public ActionResult Details(int id)
{
	Option<Movie> movie = db.Movies.Find(id);

	return movie
		.Match<ActionResult>(
			movie => View(movie),
			() => HttpNotFound());
}

wyglądają słabo i już istnieją w języku sposoby na radzenie sobie z nimi.

0

No cóż :/ Nie ma nic za darmo :D Chociaż tyle, że można prosto pozbyć się boilerplate'u z kontrolera.

0

Przecież ten kod wyżej jest tym samym, co

public ActionResult Details(int id)
{
	Movie? movie = db.Movies.Find(id);

	return movie.HasValue ?
		   View(movie) :
		   (ActionResult)HttpNotFound();
}

a jak wejdzie to https://github.com/dotnet/csharplang/issues/2460 do C#

to jeszcze bardziej się uprości zapis

public ActionResult Details(int id)
{
	Movie? movie = db.Movies.Find(id);

	return movie.HasValue ?
		   View(movie) :
		   HttpNotFound();
}

i po co dodawać tu jakieś móvie.macz of actionresult(trololol, trolololo2)?

0

No ale możesz zwrócić wiele rodzajów błędów z serwisu (NotValid, NotAuthorized, ServerError). Wtedy potrzebujesz jakiejś bazowej metody, która sprawdzi typ błędu i zwróci co trzeba.

0

Niby piszemy o eliminowaniu boilerplate, ale nagle jedna metoda mapująca błędy na http jest zła, a boilerplate od v.Match<ActionResult>(X,Y); przy każdym returnie jest ok?

Jakbyś chciał, to nawet mógłbyś robić return StatusCode(numerek z enuma tego NotValid/ServerError, dane (może być null));

0
  1. Utworzyłem ten wątek, żeby ludzie wiedzieli, że nie muszą pisać w każdym projekcie swoich Resultów.
  2. Biblioteka, która podlinkowałem, służy do orkiestracji wielu operacji zwracających Result w ładny sposób, bez brzydkich if/else i wyciągania wartości z Resultów..
  3. Jak Ci się nie podoba boilerplate language-ext, to zobacz tę bibliotekę, która podlinkowałem.
0

Sprowadzanie programowania funkcyjnego do używania bądź nieużywania Maybe jest przykre.

Co do tematu to już wolę language-ext, bo nomenklatura jest mi bliższa. W praktyce nie czuję potrzeby używania żadnego, chociaż ostatnio mam podejście do language-ext i zobaczę czy warto. Póki co mam wrażenie, że te biblioteki powstały, bo ludzie zobaczyli, że jest hype na vavry, scalaz, cats i innego tego w świecie JVM, a nie dlatego, ze w C# czegoś konkretnego brakowało. Od czasu not-nullable reference types to główny powód z nich korzystania (co widać po tym wątku) ostatecznie zniknął.

2
nobody01 napisał(a):

Za radą @somekind każdy sobie pisze jakieś Resulty zamiast spamować wyjątkami, więc czemu by nie użyć gotowego rozwiązania, które w dodatku sporo oferuje i jest jednocześnie proste w obsłudze?

Główna moja myśl jest taka, żeby nie używać wyjątków w niewyjątkowych sytuacjach, czyli informacje o niepowodzeniu przekazywać jako wynik wykonania funkcji, a nie wyjątek. Poza tym, to ja od jakiegoś czasu sugeruję używać Either zamiast Result. (Zreszą Result to też taki Either, tylko bardziej specyficznie nazwany.)
I nie widzę powodu, by używać do tego jakiejś biblioteki, taki wystarczający do pozbycia się wyjątków Either to jakieś 20 linijek kodu.

0

@somekind A jak sobie radzisz w sytuacjach, gdy musisz wywołać w serwisie 5 innych serwisów, z których każdy zwraca Either i niektóre z tych Eitherów dobrze byłoby "rozpakować"? Zakładamy, że mamy jakąś klasę-fasadę.

0

@nobody01: Myślę, że Match sobie z tym poradzi, ale nie wiem czy dobrze rozumiem problem. Mógłbyś pokazać na jakimś przykładzie?

Bo generalnie to zawsze jest jakiś łańcuch wywołań, na banalnym przykładzie:

foreach (var item in reader.ReadData())
{
    yield return item
        .IfRight(parser.ParseInput)
        .IfRight(calculator.Calculate)
        .Match(
            errorFunc: e => e.ToString(),
            rightFunc: r => r > 10 ? "Za dużo!" : r.ToString()
        );
}
0

Jak widzę te łańcuszki powstające po użyciu monad to przypominają mi się słowa mojego opiekuna ze spotkań AA: nigdy, ale to przenigdy nie pisz kodu którego nie jesteś w stanie zrozumieć i zdebugować będąc pod wpływem procentów zaraz po przebudzeniu w środku w nocy. (AA - anonimowi architekci).

0

A jaki problem w zrozumieniu i zdebugowaniu tego kodu? To nie jest żadne rocket science, IfRight zwraca Error jeśli go dostała, a jeśli nie, to przekazuje przepływ dalej z prawidłową wartością. Alternatywą byłoby wielokrotne powtarzanie if (result.Error != null), jak ktoś lubi ify, a nie lubi DRY, to może sobie tak po pijaku pisać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1