2012-01-03 25 views
8

Sotto una funzione Compose. Se f e g sono funzioni unarie che restituiscono valori, quindi Compose(f,g) restituisce una funzione che quando viene chiamata su x esegue l'equivalente a f(g(x)).Composizione funzione

static Func<X, Z> Compose<Z, Y, X>(Func<Y, Z> f,Func<X, Y> g) 
{ return x => f(g(x)); } 

Ecco un paio di semplici Func valori che può essere composto da:

Func<int, bool> is_zero = x => { return x == 0; }; 

Func<int, int> mod_by_2 = x => { return x % 2; }; 

Ad es questo funziona:

Console.WriteLine(Compose(is_zero, mod_by_2)(4)); 

Tuttavia, se invece ho questi metodi statici equivalenti:

static bool IsZero(int n) { return n == 0; } 

static int ModBy2(int n) { return n % 2; } 

stesso esempio non funziona con quelli. Cioè questo produce un errore di compilazione:

Console.WriteLine(Compose(IsZero, ModBy2)(4)); 

tipi in modo esplicito che passano a Compose corregge il problema:

Console.WriteLine(Compose<bool, int, int>(IsZero, ModBy2)(4)); 

Esiste un modo per scrivere Compose tale che funziona sui metodi statici senza i tipi espliciti?

È un buon approccio da adottare per implementare Compose? Qualcuno può apportare miglioramenti a questo?

+0

rigidità C# 's nel trattamento dei tipi di funzione/delegato è una cosa che mi ha sempre frustrato rispetto a anatra linguaggi tipografici come JavaScript. –

risposta

10

Il problema qui non è l'uso dei metodi static ma l'uso di gruppi di metodi. Quando si utilizza un nome di funzione come espressione senza invocarlo, si tratta di un gruppo di metodi e deve passare attraverso la conversione del gruppo di metodi. Avresti lo stesso identico problema con i metodi di istanza.

Il problema che si sta verificando è che C# non può restituire un'inferenza di tipo sui gruppi di metodi. L'utilizzo di Compose(IsZero, ModBy2)) richiede che il tipo di reso sia dedotto sia per IsZero sia per ModBy2 e quindi questa operazione non riesce.

Questa è una limitazione nota nelle capacità di inferenza del compilatore C#. Eric Lippert ha scritto un lungo articolo del blog su questo particolare argomento, che copre questo problema in dettaglio

+4

Prendo atto che l'articolo è leggermente obsoleto. In questo caso particolare è corretto; non puoi fare inferenza sui gruppi di metodi perché abbiamo un problema di gallina e uovo; non possiamo determinare quali sono i tipi delegati fino a quando non sappiamo quale metodo viene scelto dal gruppo metodo e non possiamo eseguire la risoluzione di sovraccarico su un gruppo di metodi finché non conosciamo i tipi di parametro formale * delegato *. Se, al contrario, i tipi di ritorno delegato * venivano dedotti, ma i * tipi di parametri formali * erano tutti in qualche modo noti, quindi l'input dell'inferenza di tipo avrebbe funzionato sui gruppi di metodi. –

+0

_Quando si utilizza un nome di funzione come espressione senza richiamarlo, si tratta di un gruppo di metodi e deve passare attraverso la conversione del gruppo metodi._ OK. Quindi il nome "IsZero" si riferisce a un gruppo di metodi. Ma in questo caso, c'è chiaramente solo un metodo nel gruppo, e quindi nessuna ambiguità sul tipo di ritorno.Ovviamente il team del compilatore ha deciso di non approfittare di questi casi (gruppi di metodi singoli). Non sarebbe stato sbagliato fare altrimenti? (Fatemi sapere se dovrei aprire una domanda separata per questo ... :-)) – dharmatech

+0

Ovviamente, un altro caso non ambiguo sarebbe costituito da gruppi di metodi in cui tutti i metodi del gruppo hanno lo stesso tipo di ritorno. – dharmatech