Functional Programming with C#: Dynamic List Generation

Part I.  A Simple Expansion

If we define a Expand() extension method for a Func<T,T> delegate type we can use it to generate lists.  This method will calculate indefinitely in the while loop so we'll have to be careful to constrain the output.

/// <summary>
///    <para>Expands indefinately starting with the seed.</para>
///    <para>Warning: this is an infinite loop and a slice of the output must be selected</para>
/// </summary>
public static IEnumerable<T> Expand<T>(this Func<T, T> generator, T pSeedA)
{
    while (true)
    {
        yield return pSeedA;
        pSeedA = generator(pSeedA);
    }
}

For an example, if we define a delegate to calculate a single decay calculation of .99 (or 1% decay), then we can  call Expand() method passing an initial seed value and our method will calculate a never-ending list of exponentially decaying results.  We'll take the 251st item to see what our value has decayed to.

Console.WriteLine("\n\nAfter 250 intervals of decay at a rate of 0.99, the value 100000.00 is now " +
    new Func<Double, Double>(x => x * 0.99)
        .Expand(100000.00) // seed value
        .Skip(250) // skip the first 250
        .First() // get the next one
); // END Console.WriteLine()

 Similarly, we can calculate exponential growth in the same manner:

Console.WriteLine("\n\nAfter a year of a monthly compounded interest rate of .08%,  10.00 grows to " +
    new Func<Double, Double>(x => x * 1.0008)
        .Expand(10.00)
        .Skip(12)
        .First()
); // END Console.WriteLine()

Part II. An Expansion with Two Seeds

We can also define an expansion used to generate a list using two seed values where each result is combined with the previous in a recursive manner.

/// <summary>
///    <para>Expands indefinately starting with the first two seeds.</para>
///    <para>Warning: this is an infinite loop and a slice must be selected</para>
/// </summary>
public static IEnumerable<T> Expand<T>(this Func<T, T, T> generator, T pSeedA, T pSeedB)
{
    T temp;

    while (true)
    {
        yield return pSeedA;
        temp = pSeedB;
        pSeedB = generator(pSeedA, pSeedB);
        pSeedA = temp;
    }
}

Using this technique, we can easily calculate a Fibonacci sequence

// Fibonacci Sequence
new Func<Int32, Int32, Int32>((x, y) => x + y)
    .Expand(1, 2)
    .Take(40)
    .ForEach(i => Console.WriteLine(i));

Part III. Searching

We can also use our simple expansion technique for searching where we need the answer to converge to an acceptable range like in this algorithm used to calculate a root of a given number. 

/// <summary>
/// Calculates the root using the really cool "Nth roots" algorithm from
/// http://www.gizmology.net/roots.htm.
/// </summary>
private static Double CalculateRoot(Double value, Double root)
{
    return new Func<Double, Double>(guess => (guess * (root - 1) + value / Math.Pow(guess, root - 1)) / root)
        .Expand(value / root) // this is our initial guess to send to the function...
        .TakeWhile((x, y) => x != y) // if x != y then we still don't have convergence
        .Last(); // once we have converged to an answer, get the last item (the answer)
}

This "converging" is a common technique in a number of AI algorithms (such as clustering and annealing algorithms) and they could be implemented as in the code above.

The code attached to this article has definitions for the Convert(), ForEach() and TakeWhile() extension methods used in the samples above.

Until next time,
Happy coding

Up Next
    Ebook Download
    View all
    Learn
    View all