2009-02-23 8 views
12

Perché potrebbero i progettisti linguaggio C# non hanno incluso il supporto per qualcosa di simile (porting da Structure and Interpretation of Computer Programs, secondo Ed, pag 30..):Perché C# non ha funzioni annidate lessicalmente?

/// <summary>Return the square root of x.</summary> 
double sqrt(double x) { 
    bool goodEnough(double guess) { 
    return Math.Abs(square(guess) - x) < 0.001; 
    } 
    double improve(double guess) { 
    return average(guess, x/guess); 
    } 
    double sqrtIter(double guess) { 
    return goodEnough(guess) ? guess : sqrtIter(improve(guess)); 
    } 
    sqrtIter(1.0); 
} 

risposta

36

Infatti, C# ha esattamente questo.

double sqrt(double x) { 
    var goodEnough = new Func<double, bool>(guess => 
     Math.Abs(square(guess) - x) < 0.001 
    ); 
    var improve = new Func<double, double>(guess => 
     average(guess, x/guess) 
    ); 
    var sqrtIter = default(Func<double, double>); 
    sqrtIter = new Func<double, double>(guess => 
     goodEnough(guess) ? guess : sqrtIter(improve(guess)) 
    ); 
    return sqrtIter(1.0); 
} 
+2

+1. Tranne la parte ricorsiva propriamente coda. :) –

+1

Sì, C# non ottimizzerà la ricorsione della coda in un ciclo. * Quella * caratteristica manca nella lingua. – yfeldblum

+0

Grazie per aver segnalato questo! Dovrò spingere per passare a .NET 3.5 (stiamo ancora inspiegabilmente usando 2.0). –

8

Come ha detto la Giustizia, puoi farlo con C# 3.5 e lambda; se si dispone di C# 2.0, è possibile utilizzare funzioni anonime, anche se sarebbe un po 'meno sexy:

double sqrt(double x) { 
    Func<double, bool> goodEnough = delegate(double guess) { 
     return Math.Abs(square(guess) - x) < 0.001; 
    }; 
    Func<double, double> improve = delegate(double guess) { 
     return average(guess, x/guess); 
    }; 
    Func<double, double> sqrtIter = null; 
    sqrtIter = delegate(double guess) { 
     return goodEnough(guess) ? guess : sqrtIter(improve(guess)); 
    }; 
    return sqrtIter(1.0); 
} 

Edit: Ho dimenticato, Func non è definito in C# 2.0, quindi è necessario definire da soli:

public delegate TResult Func<T, TResult>(T guess);