通过函数组合推断泛型类型

发布于 2024-11-09 00:39:24 字数 1387 浏览 1 评论 0原文

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

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

结果是 FREDFRED

有没有办法使用更简单的语法来调用 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 个月前)的讲座,但他似乎不了解主流现代语言的功能方面。

所以我正在跟着做练习,但我没有使用 schema 或 lisp,而是使用 C#。并且还用 Javascript 完成了其中的一些工作。

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

Suppose I want to implement a functional composition, like this:

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

Now in practice, I can use this Compose() fn like this:

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

And the result is FREDFRED.

Is there a way to use a simpler syntax to invoke Compose? I tried like this:

        var h = Compose(ToUpper, Replicate);

...but I get a compile error:

error CS0411: The type arguments for method 'FunctionalTest.Compose(System.Func, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Quite understandable. I am wondering if it is possible to declare it differently and get the inference to actually work.


EDIT
The origin of the problem: I was watching an online lecture of an undergrad Functional Programming course, UC Berkley's CS61A. (find it on youtube). I don't have any formal training on FP, and I thought I might learn something. The prof uses scheme and he talks about how scheme + lisp are purely functional languages, and other languages are less so. He specifically identified Pascal, C, C++, and Java (but not C#) as lacking functional capabilities, and said it would be difficult to do functional composition with these languages ("Without standing on your head"). He asserted that a pointer-to-function (as available in C, C++) is not the same as a function "entity", a lambda. I get that.

Funny - he didn't mention Javascript or C#, which I consider to be mainstream languages that both have pretty good functional capabilities. (I don't know F#.)

I find it curious that this is a lecture from last year - 14 months ago - and yet he seems to be unaware of the functional aspects of mainstream, modern languages.

So I'm following along and doing exercises, but instead of using scheme or lisp, I'm using C#. And also doing some of them in Javascript.

Anyway thanks to everyone for the quality responses.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

最美的太阳 2024-11-16 00:39:25

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

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

You could pass Compose the parameter too, and have it actually evaluate the function; it should be able to infer the parameter type in that case. (You might need to still specify the return type, though.)

Other than that, no, there's no way to infer things like this in C#.

东走西顾 2024-11-16 00:39:24

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

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...

Adding to lasseespeholt's answer, if you define Compose as an extension method (renamed "Then" so that the result makes more sense):

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

you can make this fluent:

var h = toUpper.Then(replicate); // .Then(trim) etc...
蛮可爱 2024-11-16 00:39:24

以下代码可以工作:

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

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

The following code would work:

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

So maybe you can still get the readability improvement you are seeking by defining those variables only once and them reusing them throughout your tests (I'm assuming this is a test utility...)

千纸鹤 2024-11-16 00:39:24

我喜欢 Ran 的回答(+1),但我认为这使它更加简洁和漂亮。 (假设您可以按如下方式重新定义函数。)

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

var h = Compose(toUpper, replicate);

I like Ran´s answer (+1), but I think this make it a little more concise and nice. (Works under the assumption that you have the possibility to redefine the functions as follows.)

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

var h = Compose(toUpper, replicate);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文