【问题标题】:Passing multiple arguments into Predicate, Functional Programming将多个参数传递给谓词,函数式编程
【发布时间】:2018-08-19 17:44:33
【问题描述】:

我正在努力更好地理解函数式编程。提供了以下示例,此示例创建了一个谓词 lambda。然后创建一个静态方法来统计通过谓词条件的项目数。

public Predicate<string> longWords = (x) => x.Length > 10;

public static int Count<T>(T[] array, Predicate<T> predicate, int counter)
    {
        for (int i = 0; i < array.Length; i++)
        {
            if (predicate(array[i]))
            {
                counter++;
            }
        }

        return counter;
    }

我想让这个解决方案遵循Referential Transparency 原则,该原则规定您只能通过查看其参数的值来确定应用该函数的结果。

不幸的是,longWords 没有告诉我长字的真正含义,我需要向longWords 传递一个参数,告诉它使函数成为长字的长度,即不硬编码“10”。

Predicates 只接受一个参数,而使longWords 需要Predicate&lt;Tuple&lt;string,int&gt;&gt;,带来了挑战。

以下是我试图找到解决方案的尝试,以及导致的两条错误消息。

public class BaseFunctions
{
    public Predicate<Tuple<string, int>> longWords = (x) => x.Item1.Length > x.Item2;

    public static int Count<T>(T[] array, Predicate<T> predicate, int counter)
    {
        for (int i = 0; i < array.Length; i++)
        {
            /// error below: Cannot convert from 'T' to 'string'
            /// in the example provided predicate(array[i]) worked fine when the predicate had only string type
            if (predicate(new Tuple<string, int>(array[i], 10)))
            {
                counter++;
            }
        }
        return counter;
    }
}

它的用法

 BaseFunctions b = new BaseFunctions();
 string[] text = ["This is a really long string", "Not 10"];
 /// also error below on BaseFunctions.Count 'The type arguments for method BaseFunctions.Count<T>(T[], Predicate<T>, int) cannot be inferred from the usage. Try specifying the arguments explicitly
 Console.WriteLine(BaseFunctions.Count(text, b.longWords, 0).ToString());
 Console.ReadLine();

【问题讨论】:

  • 不要使用Predicate&lt;Tuple&lt;string, int&gt;&gt;,最好使用Func&lt;T, int, bool&gt;,然后将Predicate&lt;T&gt; predicate改为Func&lt;T, int, bool&gt; predicate
  • 查看stackoverflow.com/questions/665494/… 了解为什么Func 优于Predicate
  • 顺便说一句,在理想的世界中,您不会想重新发明轮子,因为我们可以实现您想要的:string[] text = { "This is a really long string", "Not 10" }; Console.WriteLine(text.Count(x =&gt; x.Length &gt; 10)); 使用 Count 扩展方法。虽然,在这种特定情况下,这很好,因为您提到这仅用于练习目的。

标签: c# functional-programming


【解决方案1】:

我愿意:

public Func<string, int, bool> longWords = (str, number) => str.Length > number;

代替:

public Predicate<Tuple<string, int>> longWords = (x) => x.Item1.Length > x.Item2;

这仅仅是因为我相信使用带有 stringint 然后返回 bool 的函数比使用 stringint 元组的谓词更容易并返回一个bool。加上这个版本的元组类型使用起来很麻烦。如果您使用C#7 及更高版本,请考虑新的元组类型。

然后将方法签名更改为:

public static int Count<T>(T[] array, Predicate<T> predicate, int counter)

到:

public static int Count<T>(T[] array, Func<T, int, bool> predicate, int counter)

为了适应上述委托类型的变化。

那么if条件需要从:

if (predicate(new Tuple<string, int>(array[i], 10)))

到:

if (predicate(array[i], 10))

为了适应上述委托类型的变化。

另外,请注意,在 C# 中,您需要像这样定义数组:

string[] text = { "This is a really long string", "Not 10" };

而不是[ ] 大括号。

现在你的使用代码变成了:

BaseFunctions b = new BaseFunctions();
string[] text = { "This is a really long string", "Not 10" };

Console.WriteLine(BaseFunctions.Count(text, b.longWords, 0).ToString());
Console.ReadLine();

【讨论】:

  • 美丽的答案。是的,我在字符串数组声明方面犯了一个愚蠢的错误!
  • 虽然此答案是对您的问题的直接回答,但我认为可能值得指出原始解决方案 具有引用透明性。 longwords 函数是 Count 函数的输入之一,因此可用于推断函数调用的结果。事实上,这就是所有高阶函数 (HOF) 的工作方式。它们将函数作为参数,并且该函数专门 HOF。这里,Count 是 HOF,longwords 用于确定 Count 的数量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多