2009-02-23 5 views
12

Dlaczego nie może projektanci C# język obejmowały wsparcie dla czegoś takiego (przeniesiony z Structure and Interpretation of Computer Programs, drugie wydanie, str. 30).:Dlaczego funkcja C# nie ma funkcji zagnieżdżonych leksykalnie?

/// <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); 
} 

Odpowiedz

36

W rzeczywistości, C# ma dokładnie to.

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. Z wyjątkiem właściwie rekurencyjnej części ogonowej. :) –

+1

Tak, C# nie zoptymalizuje rekursji ogona w pętli. * Brak tej funkcji w danym języku. – yfeldblum

+0

Dzięki za wskazanie tego! Będę musiał naciskać na przejście na .NET 3.5 (w niewytłumaczalny sposób używamy 2.0). –

8

Podobnie jak powiedział Justice, można to zrobić za pomocą C 3.5 i lambdas; jeśli masz C# 2.0, można użyć funkcji anonimowych, choć byłoby to nieco mniej 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: Zapomniałem, Func nie jest zdefiniowane w C# 2.0, więc trzeba go definiować siebie:

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