开发者

Recursively execute funcs in list

Given a list of Func<string, string>, is it possible to write a statement that iterates through the list and returns the result like so:

string result = f1(f2(f..(input));

I have the following code (that works), but I'm not satisfied with the temporary variable.

public static string WrapEachElementWith<T>
    (   this IEnumerable<T> target, 
        params Func<string, string>[] func )
{
    string result = string.Empty;
    target.Each(s =>
                    {
                        var tmp = s.ToString();
                        func.Reverse().Each(x => tmp = x(tmp));
                        result += tmp;
                    });
    return result;
}

How to simplify / refactor?

UPDATE: I should have provided more background. I'm playing around with Functional programming in c# after seeing higher order JavaScript session and John's abusive c# session at Oredev.

The aim is to generate html.

var TABLE = WrapWith("TABLE");
var TR = WrapWith("TR");
var TD = WrapWith("TD");
const string expected = "<TABLE><TR><TD>1</TD></TR><TR><TD>2</TD></TR></TABLE>";

var result = TABLE(stringArray.WrapEachWith(TR, TD));
result.ShouldEqual(expected);

static Func<String, String> WrapWith(string element)
{
    var startTag = '<' + element + '>';
    var en开发者_运维技巧dTag = "</" + element + '>';
    return s => startTag + s + endTag;
}


It looks to me like you're doing four things:

  • Converting each item to a string
  • Applying the functions in turn
  • Applying that composite function to each string in a sequence
  • Joining the results together (inefficiently)

I would separate out those four aspects - in particular, string.Join works well enough for the fourth part, and Enumerable.Select does the third one.

I would also avoid reversing the order of the operations - I would expect the first operation I specify to be the first one applied, personally.

So, I would rewrite this method to return a Func<string, string> which could then be used with Select and Join. For example:

public static Func<string, string> Compose(params Func<string, string> funcs)
{
    return input => {
        string current = input;
        foreach (var func in funcs)
        {
            current = func(current);
        }
        return current;
    };
}

You could, of course, make this generic itself, with a signature of:

public static Func<T, T> Compose(params Func<T, T> funcs)

You would then call it with something like:

var composite = Compose<string>(FirstFunction, SecondFunction, ThirdFunction);

var query = string.Join("", items.Select(x => x.ToString())
                                 .Select(composite));


public static string WrapEachElementWith
    (   string input, 
        params Func<string, string>[] func )
{
    foreach (var f in func.Reverse())
        input = f(input);
    return input;
}

Not sure why you need template parameter, all the functions map string to string, right?

Note that there's no Each extension of IEnumerable, so you'll have to resort to foreach or write your own Each.

Edit:
your code actually applies this function to all the values from the list, so the actual code would be something like:

public static string F<T>
    (   this IEnumerable<T> target, 
        params Func<string, string>[] func )
{
    target.Select(item => WrapEachElementWith(item.ToString(), func))
          .Aggregate((sum, cur) => sum + cur);
}

As @Jon already mentioned, summing up this way is pretty inefficient, therefore you perhaps would like to put it this way:

string.Join("", target.Select(
                  item => WrapEachElementWith(item.ToString(), func)));


This guy wrote an entire ray tracer using LINQ. I haven't looked at his code that closely, but he describes using a technique called a "Y-combinator" to create recursion in a LINQ statement. He references this blog posting, which gives a detailed description of these recursive lambda expressions.

I don't know if that's quite what you're looking for, but it might get you off on the right footing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜