gpt4 book ai didi

scala - 不同函数式编程概念之间的关系

转载 作者:行者123 更新时间:2023-12-02 01:57:36 25 4
gpt4 key购买 nike

我自己理解函数式编程的不同概念:副作用、不变性、纯函数、引用透明。但是我无法在脑海中将它们连接在一起。例如,我有以下问题:

  • ref. 之间的关系是什么?透明度和不变性。一个是否暗示另一个?
  • 有时副作用和不变性可以互换使用。这是正确的吗?
  • 最佳答案

    这个问题需要一些特别挑剔的答案,因为它是关于定义通用词汇的。

    首先,一个功能是输入的“域”和输出的“范围”(或共域)之间的一种数学关系。每个输入都会产生一个明确的输出。例如整数加法函数+接受域中的输入 Int x Int并产生范围内的输出 Int .

    object Ex0 {
    def +(x: Int, y: Int): Int = x + y
    }

    给定 x 的任何值和 y , 清楚 +将始终产生相同的结果。这是一个函数。如果编译器特别聪明,它可以插入代码来为每对输入缓存此函数的结果,并执行缓存查找作为优化。这里显然是安全的。

    问题在于,在软件中,术语“函数”有些被滥用:尽管函数接受在其签名中声明的参数和返回值,但它们也可以读取和写入某些外部上下文。例如:
    class Ex1 {
    def +(x: Int): Int = x + Random.nextInt
    }

    我们不能再将其视为数学函数,因为对于给定值 x , +可以产生不同的结果(取决于随机值,它不会出现在 + 的签名中的任何地方)。 +的结果不能如上所述安全地缓存。所以现在我们有一个词汇问题,我们通过说 Ex0.+ 来解决这个问题。是 , 和 Ex1.+不是。

    好的,既然我们现在已经接受了某种程度的杂质,我们需要定义我们所谈论的杂质类型!在这种情况下,我们已经说过不同之处在于我们可以缓存 Ex0.+的结果与其输入相关联 xy ,而且我们不能缓存 Ex1.+的结果与其输入相关联 x .我们用来描述可缓存性(或更恰本地说,函数调用与其输出的替代性)的术语是 引用透明度 .

    所有纯函数都是引用透明的,但一些引用透明函数不是纯函数。例如:
    object Ex2 {
    var lastResult: Int
    def +(x: Int, y: Int): Int = {
    lastResult = x + y
    lastResult
    }
    }

    在这里,我们没有从任何外部上下文中读取数据,而是 Ex2.+ 产生的值。对于任何输入 xy将始终是可缓存的,如 Ex0 .这是引用透明的,但它确实有 副作用 ,用于存储函数计算的最后一个值。其他人可以稍后过来抢 lastResult ,这将使他们对 Ex2.+ 发生的事情有一些偷偷摸摸的了解!

    A side note: you can also argue that Ex2.+ is not referentially transparent, because although caching is safe with respect to the function's result, the side effect is silently ignored in the case of a cache "hit." In other words, introducing a cache changes the program's meaning, if the side effect is important (hence Norman Ramsey's comment)! If you prefer this definition, then a function must be pure in order to be referentially transparent.



    现在,这里要注意的一件事是,如果我们调用 Ex2.+连续两次或多次使用相同的输入, lastResult不会改变。调用n次方法的副作用相当于只调用一次方法的副作用,所以我们说 Ex2.+幂等 .我们可以改变它:
    object Ex3 {
    var history: Seq[Int]
    def +(x: Int, y: Int): Int = {
    result = x + y
    history = history :+ result
    result
    }
    }

    现在,每次我们拨打 Ex3.+ ,历史改变了,所以函数不再是幂等的。

    好的,到目前为止的回顾: 函数是一种既不读取也不写入任何外部上下文的函数。两者都是 引用透明 无副作用 .从某些外部上下文读取的函数不再是引用透明的,而写入某些外部上下文的函数不再没有副作用。最后,一个函数在使用相同的输入多次调用时具有与只调用一次相同的副作用,称为 幂等 .请注意,没有副作用的函数,例如纯函数,也是幂等的!

    那么如何 可变性 不变性 玩到这一切?嗯,回头看看 Ex2Ex3 .他们引入了可变 var s。 Ex2.+的副作用和 Ex3.+是变异他们各自的 var !所以可变性和副作用是相辅相成的。仅对不可变数据进行操作的函数必须没有副作用。它可能仍然不是纯的(也就是说,它可能不是引用透明的),但至少不会产生副作用。

    一个合乎逻辑的后续问题可能是:“纯函数式风格有什么好处?”这个问题的答案更复杂;)

    关于scala - 不同函数式编程概念之间的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12115312/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com