我正在学习函数编程,我想知道:
1)如果我的ForEach
扩展方法是纯粹的?我打电话的方式似乎违反了"不要把对象弄得乱七八糟",对吧?
public static void ForEach(this IEnumerable source, Action action) { foreach ( var item in source ) action(item); } static void Main(string[] args) { List cats = new List () { new Cat{ Purring=true,Name="Marcus",Age=10}, new Cat{ Purring=false, Name="Fuzzbucket",Age=25 }, new Cat{ Purring=false, Name="Beanhead",Age=9 }, new Cat{Purring=true,Name="Doofus",Age=3} }; cats.Where(x=>x.Purring==true).ForEach(x => { Console.WriteLine("{0} is a purring cat... purr!", x.Name); }); // ************************************************* // Does this code make the extension method impure? // ************************************************* cats.Where(x => x.Purring == false).ForEach(x => { x.Purring = true; // purr,baby }); // all the cats now purr cats.Where(x=>x.Purring==true).ForEach(x => { Console.WriteLine("{0} is a purring cat... purr!", x.Name); }); } public class Cat { public bool Purring; public string Name; public int Age; }
2)如果不纯,那么代码是不是很糟糕?我个人认为它使代码看起来比旧的更清晰foreach ( var item in items) { blah; }
,但我担心,因为它可能是不纯的,它可能会弄得一团糟.
3)如果它返回IEnumerable
而不是代码是坏代码void
吗?我会说,只要它是不纯的,是的,这将是非常糟糕的代码,因为它会鼓励链接一些会修改链的东西.例如,这是不好的代码?
// possibly bad extension public static IEnumerableForEach (this IEnumerable source, Action action) { foreach ( var item in source ) action(item); return source; }
MichaelGG.. 12
杂质并不一定意味着糟糕的代码.许多人发现使用副作用解决问题很容易和有用.关键是首先要知道如何以纯粹的方式做到这一点,所以你会知道什么时候杂质是合适的:).
.NET在类型系统中没有纯度的概念,因此接受任意委托的"纯粹"方法总是不纯的,这取决于它的调用方式.例如,"Where",又名"filter",通常被认为是纯函数,因为它不会修改其参数或修改全局状态.
但是,没有什么可以阻止你将这些代码放在Where的参数中.例如:
things.Where(x => { Console.WriteLine("um?"); return true; }) .Count();
所以这肯定是Where的不纯用法.Enumerables可以在迭代时做任何他们想做的事.
你的代码不好吗?没有.使用foreach循环就像"不纯"一样 - 你仍在修改源对象.我一直在编写这样的代码.将一些选择,过滤器等链接在一起,然后在其上执行ForEach以调用某些工作.你是对的,它更干净,更容易.
示例:ObservableCollection.由于某种原因,它没有AddRange方法.所以,如果我想添加一些东西,我该怎么办?
foreach(var x in things.Where(y => y.Foo > 0)) { collection.Add(x)); }
要么
things.Where(x => x.Foo > 0).ForEach(collection.Add);
我更喜欢第二个.至少,我看不出它如何被解释为比第一种方式更糟糕.
什么时候代码不好?当它在一个不期望的地方执行副作用代码时.这是我使用Where的第一个例子的情况.即便如此,有时候范围非常有限且使用情况很明显.
链接ForEach
我编写的代码就是这样做的.为了避免混淆,我会给它另一个名字.主要的困惑是"这是立即评估还是懒惰?".ForEach意味着它将立即执行一个循环.但是返回IEnumerable的东西意味着将根据需要处理这些项目.所以我建议给它另一个名字("Process","ModifySeq","OnEach"......类似的东西),并让它变得懒惰:
public static IEnumerableOnEach(this IEnumerable src, Action f) { foreach(var x in src) { f(x); yield return x; } }
Brian.. 6
它不纯,因为它可以称为不纯的方法.我认为通过典型的定义,纯度是一个传递闭包 - 只有当它调用的所有函数(直接或间接)都是纯粹的,或者如果这些函数的效果被封装时(例如它们只是改变非转义),函数才是纯的.局部变量).
杂质并不一定意味着糟糕的代码.许多人发现使用副作用解决问题很容易和有用.关键是首先要知道如何以纯粹的方式做到这一点,所以你会知道什么时候杂质是合适的:).
.NET在类型系统中没有纯度的概念,因此接受任意委托的"纯粹"方法总是不纯的,这取决于它的调用方式.例如,"Where",又名"filter",通常被认为是纯函数,因为它不会修改其参数或修改全局状态.
但是,没有什么可以阻止你将这些代码放在Where的参数中.例如:
things.Where(x => { Console.WriteLine("um?"); return true; }) .Count();
所以这肯定是Where的不纯用法.Enumerables可以在迭代时做任何他们想做的事.
你的代码不好吗?没有.使用foreach循环就像"不纯"一样 - 你仍在修改源对象.我一直在编写这样的代码.将一些选择,过滤器等链接在一起,然后在其上执行ForEach以调用某些工作.你是对的,它更干净,更容易.
示例:ObservableCollection.由于某种原因,它没有AddRange方法.所以,如果我想添加一些东西,我该怎么办?
foreach(var x in things.Where(y => y.Foo > 0)) { collection.Add(x)); }
要么
things.Where(x => x.Foo > 0).ForEach(collection.Add);
我更喜欢第二个.至少,我看不出它如何被解释为比第一种方式更糟糕.
什么时候代码不好?当它在一个不期望的地方执行副作用代码时.这是我使用Where的第一个例子的情况.即便如此,有时候范围非常有限且使用情况很明显.
链接ForEach
我编写的代码就是这样做的.为了避免混淆,我会给它另一个名字.主要的困惑是"这是立即评估还是懒惰?".ForEach意味着它将立即执行一个循环.但是返回IEnumerable的东西意味着将根据需要处理这些项目.所以我建议给它另一个名字("Process","ModifySeq","OnEach"......类似的东西),并让它变得懒惰:
public static IEnumerableOnEach(this IEnumerable src, Action f) { foreach(var x in src) { f(x); yield return x; } }
它不纯,因为它可以称为不纯的方法.我认为通过典型的定义,纯度是一个传递闭包 - 只有当它调用的所有函数(直接或间接)都是纯粹的,或者如果这些函数的效果被封装时(例如它们只是改变非转义),函数才是纯的.局部变量).