Questions tagged «pure-function»

纯函数是在给定相同参数的情况下始终对同一事物求值的函数,不能更改或依赖任何外部状态。

6
记忆的纯函数本身是否被视为纯函数?
假设fn(x)是一个纯粹的函数,它执行一些昂贵的操作,例如返回的素数列表x。 假设我们制作了一个相同功能的记忆版本memoizedFn(x)。对于给定的输入,它始终返回相同的结果,但它会保留先前结果的专用缓存以提高性能。 从形式上来讲,被memoizedFn(x)认为是纯洁的? 还是在FP讨论中有其他名称或限定词来指代此功能?(即,具有副作用的函数可能会影响后续调用的计算复杂性,但可能不会影响返回值。)

7
您怎么称呼一个函数,其中相同的输入将始终返回相同的输出,但也会产生副作用?
假设我们有一个正常的纯函数,例如 function add(a, b) { return a + b } 然后我们对其进行更改,使其具有副作用 function add(a, b) { writeToDatabase(Math.random()) return a + b; } 据我所知,它并不是纯函数,因为我经常听到人们称纯函数为“无副作用的函数”。但是,就其对于相同输入将返回相同输出的事实而言,它的行为确实类似于纯函数。 这种函数类型是否有其他名称,是未命名的,还是实际上是纯函数,而我对纯函数的定义有误?

5
捕获/抛出异常是否会使原本纯净的方法不纯?
以下代码示例为我的问题提供了上下文。 用委托初始化Room类。在Room类的第一个实现中,没有防范引发异常的委托的措施。此类异常将上升到North属性,在该North属性上评估委托(请注意:Main()方法演示了如何在客户端代码中使用Room实例): public sealed class Room { private readonly Func<Room> north; public Room(Func<Room> north) { this.north = north; } public Room North { get { return this.north(); } } public static void Main(string[] args) { Func<Room> evilDelegate = () => { throw new Exception(); }; var kitchen = new Room(north: …

4
是否有充分的理由使纯函数不公开?
我和一位同事进行了一些辩论。简而言之,是否有充分的理由隐藏/封装纯函数? “纯”是指维基百科定义: 始终从相同的输入返回相同的结果。(出于讨论的Foo Create(){ return new Foo(); }目的,如果Foo不具有值语义,则认为这是不纯的。) 不使用可变状态(局部变量除外)或I / O。 不会产生副作用。

2
何时在构造函数上使用[Pure]?
我正在学习.NET中的代码协定,并且试图了解纯构造函数的概念。该代码合同文档状态: 合同中调用的所有方法都必须是纯函数。也就是说,它们不得更新任何先前存在的状态。允许使用纯方法修改进入纯方法后创建的对象。 并且PureAttribute文档指出: 指示类型或方法是纯类型,即,它不进行任何可见状态更改。 对于方法,我理解这些语句,但是构造函数呢?假设您有一个像这样的课程: public class Foo { public int Value { get; set; } public Foo(int value) { this.Value = value; } } 显然,此构造函数确实会影响新Foo对象的状态,但是它没有其他副作用(例如,它不操纵任何参数或调用任何非纯方法)。这是候选人[Pure]吗?[Pure]在构造函数上放置属性的意义是什么?何时应该在自己的代码中执行此操作?

5
如果将函数作为参数,函数是否立即不纯?
由于输入参数的纯度直到运行时才是未知的,如果将函数作为输入参数,该函数是否立即被认为是不纯的? 相关:如果一个函数应用了一个在函数外部定义的纯函数,但没有作为参数传递,那么它是否满足纯函数的要求,即输出是否仅取决于输入,它是否仍然是纯函数? 对于上下文,我正在用JavaScript编写功能代码。

6
纯功能vs告诉,不要问?
“函数的理想参数个数为零”是完全错误的。理想的参数数目恰好是使函数不受副作用影响所需的数目。少于这个数目,您不必要地导致您的功能不纯净,从而迫使您远离成功之路,攀登痛苦的梯度。有时“鲍勃叔叔”会在他的建议下出现。有时他错得很厉害。他的零论点建议就是后者的一个例子 (来源:@David Arno在此站点上的另一个问题下的评论) 该评论获得了133个投票的惊人成绩,这就是为什么我想更加关注它的优点。 据我所知,编程有两种不同的方式:纯函数式编程(此评论令人鼓舞)和告诉,不要问(不时建议在本网站上推荐)。AFAIK这两个原则从根本上是不兼容的,彼此之间几乎是相反的:纯函数可以概括为“仅返回值,没有副作用”,而告诉,不问可以概括为“不返回任何东西,只有副作用”。另外,我有点困惑,因为我认为告诉,不要问,它被视为OO范式的核心,而纯函数则被视为功能范式的核心-现在,我看到了OO中推荐的纯函数! 我想开发人员应该选择这些范例之一并坚持下去吗?好吧,我必须承认,我永远也无法跟随自己。通常,返回值对我来说似乎很方便,而且我真的看不到如何仅凭副作用实现我想达到的目标。通常,对我来说副作用很方便,而且我真的看不到如何仅通过返回值就能达到我想要达到的目的。而且,有时(我想这太可怕了),我有两种方法都能做到。 但是,从这133个投票中,我认为当前纯函数式编程正在“取胜”,因为它已成为一种共识,说出来更好,不要问。它是否正确? 因此,在这个反模式化游戏的示例中,我尝试制作:如果我想使其符合纯功能范式-怎么办?! 对我来说,拥有战斗状态似乎是合理的。由于这是基于回合的游戏,因此我将战斗状态保留在字典中(多人游戏-可能有许多玩家同时进行许多战斗)。每当玩家回合时,我都会在战斗状态上调用适当的方法,该方法会(a)相应地修改状态,然后(b)向玩家返回更新,这些更新会序列化为JSON,并且基本上只是告诉他们发生了什么板。我想,这是在公然违反两项原则的同时。 好的-如果我确实想,我可以制定一个方法返回战斗状态,而不是就地修改它。但!然后,我是否将不得不复制战斗状态中的所有内容,只是为了返回一个全新的状态,而不是就地进行修改? 现在,如果此举是一种攻击,那么我可以返回一个更新了HP的角色?问题是,这不是那么简单:游戏规则,一举一动不仅会消除一部分玩家的生命值,而且往往会产生更多的影响。例如,它可能会增加字符之间的距离,应用特殊效果等。 对我来说,只需修改适当的状态并返回更新就简单得多了。 但是,经验丰富的工程师将如何解决这个问题?


5
计算函数是否纯函数
根据维基百科: 在计算机编程中,如果关于函数的以下两个语句均成立,则函数可以描述为纯函数:在给定相同的参数值的情况下,函数始终求值相同的结果值。函数结果值不能依赖于任何隐藏的信息或状态,这些信息或状态可能随着程序执行的进行或程序的不同执行之间的变化而变化,也不能依赖于I / O设备的任何外部输入。结果评估不会引起任何语义上可观察到的副作用或输出,例如可变对象的突变或输出到I / O设备。 我想知道是否有可能编写一个可以计算一个函数是否纯净的函数。JavaScript中的示例代码: function sum(a,b) { return a+b; } function say(x){ console.log(x); } isPure(sum) // True isPure(say) // False

2
函数式编程如何处理从多个位置引用同一对象的情况?
我正在阅读和听到,人们(也在此站点上)经常赞美函数式编程范例,强调使所有内容保持不变是多么好的。值得注意的是,人们甚至在传统的命令式OO语言(例如C#,Java或C ++)中也提出了这种方法,不仅是在像Haskell这样的纯函数式语言中,这种语言迫使程序员这样做。 我觉得很难理解,因为我发现可变性和副作用...很方便。但是,考虑到人们当前如何谴责副作用并认为是在可能的情况下消除它们的一种好习惯,我相信如果我想成为一名合格的程序员,我必须让我的乔妮开始对这种范例有一些更好的了解...因此,我的问。 当我发现功能范式存在问题时,一个地方就是自然地从多个地方引用一个对象。让我用两个例子来描述它。 第一个例子是我打算在业余时间制作的C#游戏。这是一种基于回合制的网络游戏,其中两个玩家都有4个怪物组成的团队,并且可以将一个怪物从其团队中移到战场上,在那里它将面对对方玩家发送的怪物。玩家还可以从战场上召回怪物,并用其团队中的另一个怪物代替它们(类似于口袋妖怪)。 在这种情况下,可以从至少2个地方自然引用单个怪物:玩家的团队和战场,其中引用了两个“活动”怪物。 现在,让我们考虑一个怪物被击中并失去20点生命值时的情况。在命令式范式的括号内,我修改了此怪物的health字段以反映此更改-这就是我现在正在做的。但是,这使Monster类可变且相关的函数(方法)不纯净,我认为到目前为止,这仍被认为是一种不好的做法。 即使我允许自己以低于理想状态的方式编写游戏代码,以便希望在将来的某个时候完成游戏,但我还是想知道并理解它应该如何写得正确。因此:如果这是设计缺陷,如何解决? 就我所知,在函数式中,我将对此Monster对象进行复制,使其与旧对象相同,除了该字段。并且该方法suffer_hit将返回此新对象,而不是就地修改旧对象。然后,我同样会复制Battlefield对象,并保持其所有字段相同(除了该怪物)。 这至少有两个困难: 层次结构可以比Just- Battlefield>的简化示例更深入Monster。我必须对所有字段(除了一个字段)进行这种复制,并在此层次结构中一直返回一个新对象。这将是样板代码,我发现这很烦人,特别是因为功能编程应该减少样板代码。 但是,一个更为严重的问题是,这将导致数据不同步。野外活动的怪物的生命值会降低。但是,从其控制者那里引用的同一个怪物Team不会。如果我改用命令式风格,那么对数据的每次修改都可以在所有其他代码位置立即看到,在这种情况下,我发现它真的很方便- 但是我得到东西的方式正是人们所说的势在必行! 现在,可以通过Team每次攻击之后的旅程来解决此问题。这是额外的工作。但是,如果以后突然可以从更多地方引用怪物,该怎么办?例如,如果我具有一种能力,例如,让一个怪物专注于另一个不一定在场上的怪物(我实际上正在考虑这种能力)怎么办?我肯定会记得在每次攻击后立即进行一次聚焦怪物的旅程吗?这似乎是一个定时炸弹,随着代码变得越来越复杂,它会爆炸,所以我认为这是没有解决方案的。 当我遇到相同的问题时,从第二个示例中得出一个更好的解决方案的想法。在学术界,我们被告知要在Haskell中编写我们自己设计的语言的口译员。(这也是我被迫开始了解FP是什么的方式)。当我实现闭包时出现了问题。现在可以再次从多个位置引用同一作用域:通过保存该作用域的变量以及任何嵌套作用域的父作用域!显然,如果通过指向该范围的任何引用对该范围进行了更改,则此更改也必须通过所有其他引用可见。 我提出的解决方案是为每个范围分配一个ID,并在Statemonad中保存所有范围的中央字典。现在,变量将仅保留它们绑定到的作用域的ID,而不是作用域本身,并且嵌套作用域还将保留其父作用域的ID。 我猜想在我的怪物战斗游戏中可以尝试相同的方法。相反,它们拥有保存在中央怪物词典中的怪物ID。 但是,我再次看到这种方法存在问题,使我无法毫不犹豫地接受它作为解决问题的方法: 它再次是样板代码的来源。它使单线必然变成三线:以前对单个字段进行单行就地修改现在需要(a)从中央字典中检索对象(b)进行更改(c)保存新对象到中央字典。同样,持有对象和中央字典的id而不是拥有引用会增加复杂性。因为FP的广告是为了减少复杂性和样板代码,所以这暗示我做错了。 我还打算写一个似乎更严重的第二个问题:这种方法引入了内存泄漏。无法访问的对象通常将被垃圾回收。但是,即使没有可访问的对象都引用此特定ID,也无法对中央词典中保存的对象进行垃圾回收。尽管从理论上讲,仔细的编程可以避免内存泄漏(一旦不再需要,我们可以小心地从中央字典中手动删除每个对象),但是这很容易出错,并且FP广告宣传增加了程序的正确性,因此这可能再次不是正确的方法。 但是,我及时发现它似乎是一个已解决的问题。Java提供WeakHashMap了可用于解决此问题的方法。C#提供了类似的功能- ConditionalWeakTable尽管根据文档,它是供编译器使用的。在Haskell中,我们有System.Mem.Weak。 存储此类词典是解决此问题的正确功能解决方案,还是我看不到更简单的解决方案?我想象这样的词典的数量很容易增长,而且非常糟糕。因此,如果这些字典区域也应该是不可变的,这可能意味着很多参数传递,或者在支持该功能的语言中,表示单子计算,因为字典将以单子形式保存(但是我再次将其读为纯函数式)语言,尽可能少的代码应该是monadic,而这个字典解决方案会将几乎所有代码都放在Statemonad内;这再次使我怀疑这是否是正确的解决方案。) 经过一番考虑之后,我想我会再问一个问题:构建这样的词典能获得什么?许多专家认为,命令式编程的错误之处在于某些对象的更改会传播到其他代码段。为了解决这个问题,对象应该是不可变的-正是出于这个原因,如果我正确理解的话,对它们所做的更改应该在其他地方不可见。但是现在,我担心对过期数据进行操作的其他代码段,因此发明了中央字典,以便……将某些代码段中的更改再次传播到其他代码段中!因此,我们不是回到带有所有假定缺点的命令式样式,而是增加了复杂性吗?

3
为什么在函数式编程中不鼓励使用赋值运算符或循环?
如果我的函数满足以下两个要求,我相信Sum 返回给定条件下列表项的总和的函数,其中项在给定条件下的评估结果为true,这称为纯函数,不是吗? 1)对于给定的一组i / p,无论何时调用函数,都将返回相同的o / p 2)它没有任何副作用 public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){ int result = 0; foreach(var item in numbers) if(predicate(item)) result += item; return result; } 范例: Sum(x=>x%2==0, new List<int> {1,2,3,4,5...100}); 我之所以问这个问题,是因为我几乎每时每刻都在建议人们避免使用赋值运算符和循环,因为它是命令式编程风格。那么上面的示例在函数编程的上下文中使用循环和赋值运算符会出错吗?

4
这种方法纯吗?
我有以下扩展方法: public static IEnumerable<T> Apply<T>( [NotNull] this IEnumerable<T> source, [NotNull] Action<T> action) where T : class { source.CheckArgumentNull("source"); action.CheckArgumentNull("action"); return source.ApplyIterator(action); } private static IEnumerable<T> ApplyIterator<T>(this IEnumerable<T> source, Action<T> action) where T : class { foreach (var item in source) { action(item); yield return item; } } 它只是在返回序列之前对序列的每个项目执行操作。 我想知道是否应该将Pure属性(来自Resharper注释)应用于此方法,并且可以看到支持和反对该参数的参数。 优点: …
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.