var exactlyForty = people.Where(person => person.Age == 40);
Where 方法是 IEnumerable 接口上的扩展方法,其中在本例中,T 是某种Person 类。
这在 .NET 中称为“Linq to Objects”,但在其他地方称为序列或流或“惰性”列表上的纯函数式编程(同一事物的所有不同名称)。
I think you're confusing terms from different languages. You seem to be using "Functor" in the C++ or Java sense, e.g. see the wikipedia page. In C++, it's an object of a class that overloads the function-call operator, so it can be used as a function but with state.
This is logically the same thing as a delegate bound to an instance method in C# (or any .NET language).
There are three ways to write such a thing. First, you can write an ordinary method, and then assign the name of the method to a delegate variable.
The advantage of the last two is that the body of the method can read and write local variables in the containing method.
The advantage of lambda syntax over anon-methods are that it is more succinct and it does type inference on parameters.
Update: The advantage of anon-methods (delegate keyword) over lambdas is that you can omit the parameters altogether if you don't need them:
// correct way using lambda
button.Click += (sender, eventArgs) => MessageBox.Show("Clicked!");
// compile error - wrong number of arguments
button.Click += () => MessageBox.Show("Clicked!");
// anon method, omitting arguments, works fine
button.Click += delegate { MessageBox.Show("Clicked!"); };
I know of only one situation where this is worth knowing, which is when initializing an event so that you don't have to check for null before firing it:
event EventHandler Birthday = delegate { };
Avoids a lot of nonsense elsewhere.
Finally, you mention that there are four kinds of functor. In fact there are an infinity of possibly delegate types, although some authors may have their favourites and there obviously will be some common patterns. An Action or Command takes no parameters and returns void, and a predicate takes an instance of some type and returns true or false.
In C# 3.0, you can whip up a delegate with up to four parameters of any types you like:
Func<string, int, double> f; // takes a string and an in, returns a double
Re: Updated Question
You ask (I think) if there are many use cases for lambdas. There are more than can possibly be listed!
You most often see them in the middle of larger expressions that operate on sequences (lists computed on-the-fly). Suppose I have a list of people, and I want a list of people exactly forty years old:
var exactlyForty = people.Where(person => person.Age == 40);
The Where method is an extension method on the IEnumerable<T> interface, where T in this case is some kind of Person class.
This is known in .NET as "Linq to Objects", but known elsewhere as pure functional programming on sequences or streams or "lazy" lists (all different names for the same thing).
int[] data = { 1,2,3,4,5,6,7,8,9 };
var oddData = data.Where( i => i % 2 == 1 );
var descending = data.OrderBy(i => -i);
var asStrings = data.Select(i => i.ToString());
这里是 Where< /code> 和 OrderBy 方法是采用委托的 LINQ 扩展方法。
In .NET terms, I think what you are describing is the Delegate - and it exists in all of .NET, not just C#.
I'm not sure that a "closure" would a "type" in the same was as a comparer/predicate/transformer, since in C# terms a closure is simply an implementation detail but can be any of those three.
In .NET, delegates are used in two main ways:
as the eventing mechanism
to provide functional-style programming
The first is important, but it sounds like you are more interested in the second. In reality, they operate much like single-method interfaces... consider:
A closure is more where we bring additional scope from outside the delegate into the delegate:
int max = int.Parse(Console.ReadLine()); // perhaps 6
List<int> limited = vals.FindAll(i => i <= max);
here the max is captured into the delegate as a closure.
Re "Are classes within the framework prepaired for this?" - many are, and LINQ goes a long way to allowing this even wider. LINQ provides extension methods over (for example) all of IEnumerable<T> - meaning that collections without delegate-based access aquire them for free:
int[] data = { 1,2,3,4,5,6,7,8,9 };
var oddData = data.Where( i => i % 2 == 1 );
var descending = data.OrderBy(i => -i);
var asStrings = data.Select(i => i.ToString());
Here the Where and OrderBy methods are LINQ extension methods that take delegates.
List<int> ints = new List<int>();
ints.AddRange(new int[] { 9, 5, 7, 4, 3, 5, 3 });
ints.Sort(new Comparison<int>(delegate(int x, int y)
{
return x.CompareTo(y);
}));
// yes I am aware the ints.Sort() would yield the same result, but hey, it's just
// a conceptual code sample ;o)
// and the shorter .NET 3.5 version:
ints.Sort((x, y) =>
{
return x.CompareTo(y);
});
Interesting with terminology; my spontaneous interpretation of the term "Functor" was that it referred to anonymous methods. So that will be my take on it.
These are some of my typical uses:
Comparisons (usually for sorting a list):
List<int> ints = new List<int>();
ints.AddRange(new int[] { 9, 5, 7, 4, 3, 5, 3 });
ints.Sort(new Comparison<int>(delegate(int x, int y)
{
return x.CompareTo(y);
}));
// yes I am aware the ints.Sort() would yield the same result, but hey, it's just
// a conceptual code sample ;o)
// and the shorter .NET 3.5 version:
ints.Sort((x, y) =>
{
return x.CompareTo(y);
});
I will use this approach for comparisons, rather than having it in its own method an using a delegate for that method, in the cases where this particular sort happens in one place only. If it is likely that I will want to use the same comparison somewhere else, it gets to live in its own, reusable method.
Another of my fairly common uses is in unit testing, when the test relies on some event being raised. I have found that to be essential when unit testing workflows in Workflow Foundation:
WorkflowRuntime runtime = WorkflowHost.Runtime;
WorkflowInstance instance = runtime.CreateWorkflow(typeof(CreateFile));
EventHandler<WorkflowEventArgs> WorkflowIdledHandler = delegate(object sender, WorkflowEventArgs e)
{
// get the ICreateFileService instance from the runtime
ISomeWorkflowService service = WorkflowHost.Runtime.GetService<ISomeWorkflowService>();
// set the desired file content
service.DoSomeWork(instance.InstanceId, inputData);
};
// attach event handler
runtime.WorkflowIdled += WorkflowIdledHandler;
instance.Start();
// perform the test, and then detach the event handler
runtime.WorkflowIdled -= WorkflowIdledHandler;
In this case it is simpler to have the event handler declared as anonymous methods since it uses the instance variable that is defined in the unit test method scope. Had I intstead opted to implelment the event handler as its own separate method I would also need to figure out a way for it to pick up instance, probably by introducing a class level member, which would not seem like a perfect design in a unit test class.
There are more cases where I find this in my code, but they usually have one or two things in common:
I have no interest in referencing that piece of code from anywhere else than in that particular place.
The method needs access to data that would be out of the scope for a regular method
The real answer is that a functor is a type of mathematical object, and is "reified" by different languages in different ways. For example, suppose that you have a "container" object that stores a bunch of other objects of the same type. (For example, a set or array) Then, if your language had a method that let you 'map' over the container, so that you could call a method on each object in the container, then the container would be a functor.
In other words, a functor is a container with a method that lets you pass a method to its contained things.
Every language has its own way of doing this, and they sometimes conflate the usage. For example, C++ uses function pointers to represent the "passing in" of a method, and calls the function pointer a "functor." Delegates are just a handle on methods that you can pass in. You are using the terminology "incorrectly", just like C++ does.
Haskell gets it right. You declare that a type implements the functor interface, and then you get the mapping method.
Functions (like lambdas) are functors too, but it can be kind of hard to think of a function as a "container". In short, a function is a "container" around a return value, constructed in such a way that the return value (possibly) depends on the function's arguments.
I'm sure you mean Lambda Expressions. Those are Small Functions you can write very quickly, and they have the characteristic "=>" Operator. These are a new Feature of C# 3.0.
This Example will be a classic Transformer; to use one we need a delegate to define the signature for the Lambda Function.
delegate int Transformer(int i);
Now Declare a Lambda with this delegate:
Transformer sqr = x => x * x;
We can use it like a normal function:
Console.WriteLine(sqr(3)); //9
These are used in LINQ Queries a lot, for example to Sort (Comparer), to Search through (Predicate).
The book "C# Pocket Reference" (apart from beign the best around in my opinion, has a very good part on Lambdas. (ISBN 978-0-596-51922-3 )
发布评论
评论(5)
我认为您混淆了不同语言的术语。 您似乎在 C++ 或 Java 意义上使用“Functor”,例如请参阅维基百科页面。 在 C++ 中,它是重载函数调用运算符的类的对象,因此它可以用作函数但具有状态。
这在逻辑上与绑定到 C#(或任何 .NET 语言)中的实例方法的委托相同。
有三种方法可以写这样的东西。 首先,您可以编写一个普通方法,然后将该方法的名称分配给委托变量。
其次,可以使用 C# 2.0 中引入的匿名方法语法:
第三,可以使用 C# 3.0 中引入的 lambda 语法:
后两者的优点是方法体可以读写包含方法中的局部变量。
与非方法相比,lambda 语法的优点是它更简洁,并且可以对参数进行类型推断。
更新: 匿名方法(
delegate
关键字)相对于 lambda 的优点是,如果不需要参数,可以完全省略参数:我只知道一种情况值得了解的地方是在初始化事件时,这样您就不必在触发事件之前检查
null
:避免在其他地方出现很多废话。
最后,您提到函子有四种。 事实上,可能的委托类型有无数种,尽管有些作者可能有他们最喜欢的类型,并且显然会有一些常见的模式。
Action
或Command
不带参数并返回void
,谓词采用某种类型的实例并返回true
> 或假
。在 C# 3.0 中,您可以使用最多四个您喜欢的任何类型的参数来创建委托:
回复:更新的问题
您会问(我认为)是否有很多 lambda 用例。 还有更多的内容无法列出!
您最常在对序列进行操作的较大表达式(动态计算的列表)中间看到它们。 假设我有一个人员列表,并且我想要一个正好四十岁的人员列表:
Where
方法是IEnumerable
接口上的扩展方法,其中在本例中,T
是某种Person
类。这在 .NET 中称为“Linq to Objects”,但在其他地方称为序列或流或“惰性”列表上的纯函数式编程(同一事物的所有不同名称)。
I think you're confusing terms from different languages. You seem to be using "Functor" in the C++ or Java sense, e.g. see the wikipedia page. In C++, it's an object of a class that overloads the function-call operator, so it can be used as a function but with state.
This is logically the same thing as a delegate bound to an instance method in C# (or any .NET language).
There are three ways to write such a thing. First, you can write an ordinary method, and then assign the name of the method to a delegate variable.
Second, you can use anonymous method syntax, introduced in C# 2.0:
Thirdly, you can use lambda syntax, introduced in C# 3.0:
The advantage of the last two is that the body of the method can read and write local variables in the containing method.
The advantage of lambda syntax over anon-methods are that it is more succinct and it does type inference on parameters.
Update: The advantage of anon-methods (
delegate
keyword) over lambdas is that you can omit the parameters altogether if you don't need them:I know of only one situation where this is worth knowing, which is when initializing an event so that you don't have to check for
null
before firing it:Avoids a lot of nonsense elsewhere.
Finally, you mention that there are four kinds of functor. In fact there are an infinity of possibly delegate types, although some authors may have their favourites and there obviously will be some common patterns. An
Action
orCommand
takes no parameters and returnsvoid
, and a predicate takes an instance of some type and returnstrue
orfalse
.In C# 3.0, you can whip up a delegate with up to four parameters of any types you like:
Re: Updated Question
You ask (I think) if there are many use cases for lambdas. There are more than can possibly be listed!
You most often see them in the middle of larger expressions that operate on sequences (lists computed on-the-fly). Suppose I have a list of people, and I want a list of people exactly forty years old:
The
Where
method is an extension method on theIEnumerable<T>
interface, whereT
in this case is some kind ofPerson
class.This is known in .NET as "Linq to Objects", but known elsewhere as pure functional programming on sequences or streams or "lazy" lists (all different names for the same thing).
在 .NET 术语中,我认为您所描述的是
Delegate
- 它存在于所有 .NET 中,而不仅仅是 C#。我不确定“闭包”是否会像比较器/谓词/转换器一样“类型”,因为在 C# 术语中,闭包只是一个实现细节,但可以任何那三个。
在 .NET 中,委托有两种主要使用方式:
第一个很重要,但听起来您对第二个更感兴趣。 实际上,它们的操作方式与单方法接口非常相似...考虑一下:
闭包更多的是我们将额外的范围从委托外部引入委托到委托中:
这里是< code>max 作为闭包捕获到委托中。
回复“框架内的类是否为此做好了准备?” - 很多都是这样,LINQ 走了很长的路,让这种情况变得更广泛。 LINQ 提供了(例如)所有
IEnumerable
的扩展方法 - 这意味着没有基于委托的访问的集合可以免费获取它们:这里是
Where< /code> 和
OrderBy
方法是采用委托的 LINQ 扩展方法。In .NET terms, I think what you are describing is the
Delegate
- and it exists in all of .NET, not just C#.I'm not sure that a "closure" would a "type" in the same was as a comparer/predicate/transformer, since in C# terms a closure is simply an implementation detail but can be any of those three.
In .NET, delegates are used in two main ways:
The first is important, but it sounds like you are more interested in the second. In reality, they operate much like single-method interfaces... consider:
A closure is more where we bring additional scope from outside the delegate into the delegate:
here the
max
is captured into the delegate as a closure.Re "Are classes within the framework prepaired for this?" - many are, and LINQ goes a long way to allowing this even wider. LINQ provides extension methods over (for example) all of
IEnumerable<T>
- meaning that collections without delegate-based access aquire them for free:Here the
Where
andOrderBy
methods are LINQ extension methods that take delegates.术语有趣; 我对“Functor”一词的自发解释是它指的是匿名方法。 这就是我的看法。
这些是我的一些典型用途:
比较(通常用于对列表进行排序):
在这种特定排序发生在的情况下,我将使用这种方法进行比较,而不是在自己的方法中使用该方法的委托。仅限一处。 如果我可能想在其他地方使用相同的比较,它就会以自己的、可重用的方法存在。
我的另一个相当常见的用途是单元测试,此时测试依赖于引发的某些事件。 我发现在 Workflow Foundation 中对工作流进行单元测试时这一点至关重要:
在这种情况下,将事件处理程序声明为匿名方法会更简单,因为它使用单元测试中定义的
instance
变量方法范围。 如果我选择将事件处理程序作为其自己的单独方法来实现,我还需要找出一种方法来让它获取实例,可能是通过引入类级别成员,这看起来并不像单元测试类的完美设计。我在代码中发现了很多这样的情况,但它们通常有一两个共同点:
Interesting with terminology; my spontaneous interpretation of the term "Functor" was that it referred to anonymous methods. So that will be my take on it.
These are some of my typical uses:
Comparisons (usually for sorting a list):
I will use this approach for comparisons, rather than having it in its own method an using a delegate for that method, in the cases where this particular sort happens in one place only. If it is likely that I will want to use the same comparison somewhere else, it gets to live in its own, reusable method.
Another of my fairly common uses is in unit testing, when the test relies on some event being raised. I have found that to be essential when unit testing workflows in Workflow Foundation:
In this case it is simpler to have the event handler declared as anonymous methods since it uses the
instance
variable that is defined in the unit test method scope. Had I intstead opted to implelment the event handler as its own separate method I would also need to figure out a way for it to pick upinstance
, probably by introducing a class level member, which would not seem like a perfect design in a unit test class.There are more cases where I find this in my code, but they usually have one or two things in common:
真正的答案是,函子是一种数学对象,并且由不同的语言以不同的方式“具体化”。 例如,假设您有一个“容器”对象,它存储一堆相同类型的其他对象。 (例如,集合或数组)然后,如果您的语言有一个方法可以让您“映射”容器,以便您可以在容器中的每个对象上调用方法,那么容器将是一个函子。
换句话说,函子是一个带有方法的容器,可让您将方法传递给其所包含的事物。
每种语言都有自己的方式来做到这一点,并且有时会混淆用法。 例如,C++使用函数指针来表示方法的“传入”,并将函数指针称为“函子”。 委托只是您可以传入的方法的句柄。您“错误”地使用了术语,就像 C++ 一样。
哈斯克尔说得对。 您声明一个类型实现函子接口,然后您获得映射方法。
函数(如 lambda)也是函子,但很难将函数视为“容器”。 简而言之,函数是围绕返回值的“容器”,其构造方式使得返回值(可能)取决于函数的参数。
The real answer is that a functor is a type of mathematical object, and is "reified" by different languages in different ways. For example, suppose that you have a "container" object that stores a bunch of other objects of the same type. (For example, a set or array) Then, if your language had a method that let you 'map' over the container, so that you could call a method on each object in the container, then the container would be a functor.
In other words, a functor is a container with a method that lets you pass a method to its contained things.
Every language has its own way of doing this, and they sometimes conflate the usage. For example, C++ uses function pointers to represent the "passing in" of a method, and calls the function pointer a "functor." Delegates are just a handle on methods that you can pass in. You are using the terminology "incorrectly", just like C++ does.
Haskell gets it right. You declare that a type implements the functor interface, and then you get the mapping method.
Functions (like lambdas) are functors too, but it can be kind of hard to think of a function as a "container". In short, a function is a "container" around a return value, constructed in such a way that the return value (possibly) depends on the function's arguments.
我确定你指的是 Lambda 表达式。 这些是您可以很快编写的小函数,并且它们具有特征“=>” 操作员。 这些是 C# 3.0 的新功能。
这个例子将是一个经典的 Transformer; 要使用它,我们需要一个委托来定义 Lambda 函数的签名。
现在用这个委托声明一个 Lambda:
我们可以像普通函数一样使用它:
这些在 LINQ 查询中经常使用,例如排序(比较器)、搜索(谓词)。
《C# Pocket Reference》一书(除了我认为最好的之外,在 Lambda 方面有非常好的部分。(ISBN 978-0-596-51922-3)
I'm sure you mean Lambda Expressions. Those are Small Functions you can write very quickly, and they have the characteristic "=>" Operator. These are a new Feature of C# 3.0.
This Example will be a classic Transformer; to use one we need a delegate to define the signature for the Lambda Function.
Now Declare a Lambda with this delegate:
We can use it like a normal function:
These are used in LINQ Queries a lot, for example to Sort (Comparer), to Search through (Predicate).
The book "C# Pocket Reference" (apart from beign the best around in my opinion, has a very good part on Lambdas. (ISBN 978-0-596-51922-3 )