用函数组合推断泛型类型

本文关键字:泛型类型 组合 函数 | 更新日期: 2023-09-27 17:57:26

假设我想实现一个函数组合,如下所示:

    public Func<T,T> Compose<T>(Func<T,T> f, Func<T,T> g)
    {
        return new Func<T,T>( x => f(g(x)));
    }

现在在实践中,我可以像这样使用Compose()fn:

    public String ToUpper(String s) { return s.ToUpper(); }        
    public String Replicate(String s) { return s+s; }
    public void Run()
    {
        var h = Compose<String>(ToUpper, Replicate);
        System.Console.WriteLine("{0}", h("fred"));
    }

结果是CCD_ 1。

有没有一种方法可以使用更简单的语法来调用Compose?我试过这样:

        var h = Compose(ToUpper, Replicate);

但是我得到了一个编译错误:

错误CS0411:无法根据用法推断方法"FunctionalTest.Compose(System.Func,System.Func)"的类型参数。请尝试显式指定类型参数。

可以理解。我想知道是否有可能以不同的方式声明它,并使推理真正起作用。


编辑
问题的根源:我在看一个本科生函数编程课程的在线讲座,加州大学伯克利分校的CS61A。(在youtube上找到)。我没有接受过任何正式的FP培训,我想我可能会学到一些东西。这位教授使用scheme,他谈到scheme+lisp是纯粹的函数式语言,而其他语言则不然。他特别指出Pascal、C、C++和Java(但不是C#)缺乏函数能力,并表示用这些语言进行函数组合是很困难的("如果不站在你的头上")。他断言,指向函数的指针(在C、C++中可用)与函数"实体"(lambda)不同。我明白了。

有趣的是,他没有提到Javascript或C#,我认为它们是主流语言,都有很好的功能。(我不知道F#。)

我感到奇怪的是,这是去年——14个月前——的一次演讲,但他似乎不知道主流现代语言的功能方面。

所以我跟着做练习,但我使用的不是scheme或lisp,而是C#。也用Javascript做了一些。

无论如何,感谢大家的高质量回复。

用函数组合推断泛型类型

如果您将Compose定义为扩展方法(重命名为"Then",以便结果更有意义),则添加到lassespholt的答案中:

public static Func<T, T> Then<T>(this Func<T, T> f, Func<T, T> g)
{
    return x => g(f(x));
}

你可以说得很流利:

var h = toUpper.Then(replicate); // .Then(trim) etc...

以下代码可以工作:

Func<string, string> toUpper = ToUpper;
Func<string, string> replicate = Replicate;
// now the compiler knows that the parameters are Func<string, string>
var h = Compose(toUpper, replicate);

因此,也许您仍然可以通过只定义一次这些变量并在整个测试中重用它们来获得您所寻求的可读性改进(我假设这是一个测试实用程序…)

我喜欢冉的答案(+1),但我认为这会让它更简洁、更漂亮。(在假设您有可能重新定义以下功能的情况下工作。)

Func<string, string> toUpper = s => s.ToUpper();
Func<string, string> replicate = s => s + s;
var h = Compose(toUpper, replicate);

您也可以将参数传递给Compose,并让它实际评估函数;在这种情况下,它应该能够推断出参数类型。(不过,您可能仍然需要指定返回类型。)

除此之外,不,在C#中没有办法推断出这样的事情。