2011-08-21 12 views
13

Myślę, że mój umysł eksploduje próbując rozgryźć Funcs ... Jeśli to nie ma sensu, przepraszam, teraz to ma sens dla mnie, ale to był już długi dzień ....Konwersja Func <T, String> do Func <T, bool>

1) Zakładając, że otrzymują func, który trwa w T i wyjść ciąg:

Func<T, string> 

można przekształcić że do func, które miało w T i zwraca bool oparciu o pewnej logiki (w ten przypadek, jeśli zwracany ciąg jest pusty (String.IsNullOrWhiteSpace)?

Func<T, bool> 

2) Czy można zrobić to samo, jeśli są podane takie

Expression<Func<T, string>> 

i trzeba przekonwertować go na

Func<T, bool> 

która zwraca true/false na podstawie jeśli zwrócony ciąg jest pusty (String.IsNullOrWhiteSpace)?

Dzięki

Odpowiedz

11

dla pierwszej części można nawet zrobić jakieś "wyższe" -order funkcję:



Func<A,C> MapFun<A,B,C>(Func<A,B> input, Func<B,C> transf) 
{ 
    return a => transf(input(a)); 
} 

użytkowania z



Func <T,string> test = ... 
var result = MapFun(test, String.IsNullOrWhiteSpace); 

(mam nadzieję, typ C# typ wnioskowanie pracuje tutaj)

Jeśli zdefiniujemy to jako przedłużenie na Func robi się jeszcze prostsze:


public static class FuncExtension 
{ 
    public static Func<A,C> ComposeWith<A,B,C>(this Func<A,B> input, Func<B,C> f) 
    { 
     return a => f(input(a)); 
    } 
} 

tutaj jest bardzo prosty test:


Func<int, string> test = i => i.ToString(); 
var result = test.ComposeWith(string.IsNullOrEmpty); 

Po drugie: myślę, że możesz skompilować wyrażenie w "prawdziwą" Func, a następnie użyć powyższego kodu. see MSDN Docs on Expression.Compile

PS: przemianowany funkcję w celu lepszego dopasowania to zamierza (jest złożenie funkcji)

+0

Chyba masz na myśli "typowanie", a nie "interferencję typu";) –

+0

Dzięki! kiedy spojrzysz na odpowiedź, to ma ona sens. Wiele poprawnych odpowiedzi, ale twoja była pierwsza i kompletna, więc dostałeś czek. Dziękuję wszystkim! – Peter

3

Nie mogłeś zdefiniować go jako oddzielny Delegat:

Func<T, string> func1 = t => t.ToString(); 
Func<T, bool> func2 = t => string.IsNullOrEmpty(func1(t)); 
2

dla pierwszej części technika jest znana jako złożenie funkcji tj komponować 2 funkcje, aby utworzyć nową funkcję. W twoim przypadku masz funkcję Func<T,String> i inną funkcję (jak struny pusta lub NULL), która jest typu Func<string,bool> korzystając złożenie funkcji można komponować te dwie funkcje, aby utworzyć nową funkcję typu Func<T,Bool>

Najbardziej funkcjonalny język programowania mają ten skład funkcji już zdefiniowany w ich standardowej bibliotece lub w samym języku. Ale nie jest trudno stworzyć taką dla swojego języka, jeśli język obsługuje funkcje jako wartości pierwszej klasy.

W języku C# można użyć poniższego funkcję, która pozwoli Ci komponować funkcje:

public static Func<X,Z> Compose<X,Y,Z>(Func<X,Y> a, Func<Y,Z> b) 
{ 
    return (v) => b(a(v)); 
} 
2

do 1: Tak (Można również sparametryzować bool oraz string):

Func<T, bool> Compose<T>(Func<T, string> source, Func<string, bool>map) 
{ 
    return x => map(source(x)); 
} 

do 2 Tak, ale trzeba skompilować pierwszy wyraz:

Func<T, bool> Compose<T>(Expression<Func<T, string>> source, Func<string, bool> map) 
{ 
    return x => compose(source.Compile(), map) 
} 

.Compile skompiluje ekspresji i nto dynamiczna metoda CLR, którą można wywołać ze zwróconym delegatem.

Można użyć tego kodu:

Func<int, string> ts = i => i.ToString(); 
var result = Compose(ts, string.IsNullOrEmpty); 

Nawiasem mówiąc, w tym przypadku naprawdę powinieneś napisać funkcja wyższego rzędu. To, co tu robisz (algebraicznie), to komponowanie monoidów. Zapamiętaj function composition? f . g := f(g(x)) to co tutaj robisz.

Pomyśl o źródle jako g:A->B i mapy jako f:B->C (gdzie A, B i C są zestawy), więc wynik f . g jest h:A->C. Nawiasem mówiąc, operator . jest często wbudowany w funkcjonalne języki programowania, takie jak Haskell i osiąga to samo co funkcja compose (ale z czystszą składnią).

Powiązane problemy