Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 函数式编程是否允许局部范围对象的可变性?_Python_Language Agnostic_Functional Programming - Fatal编程技术网

Python 函数式编程是否允许局部范围对象的可变性?

Python 函数式编程是否允许局部范围对象的可变性?,python,language-agnostic,functional-programming,Python,Language Agnostic,Functional Programming,我了解到一个物体的易变性是根据它的状态来定义的,而不是根据它的身份来定义的 下面,程序在函数hailstone()中更改由名称count引用的局部作用域对象的状态 在阅读了的下面一段之后,我看到上面的代码在更改namecount所指的本地作用域对象的状态方面看起来很好(即count+=冰雹(n/2)): 忽略所有这些。功能代码有一个特点:没有副作用。它不依赖于当前函数外部的数据,也不更改当前函数外部存在的数据。其他任何“功能性”事物都可以从这个属性派生出来。学习时将其用作引导绳 那么,我如何从以

我了解到一个物体的易变性是根据它的状态来定义的,而不是根据它的身份来定义的

下面,程序在函数
hailstone()
中更改由名称
count
引用的局部作用域对象的状态

在阅读了的下面一段之后,我看到上面的代码在更改name
count
所指的本地作用域对象的状态方面看起来很好(即
count+=冰雹(n/2)
):

忽略所有这些。功能代码有一个特点:没有副作用。它不依赖于当前函数外部的数据,也不更改当前函数外部存在的数据。其他任何“功能性”事物都可以从这个属性派生出来。学习时将其用作引导绳

那么,我如何从以下方面理解本声明的含义:

在函数式编程中,改变变量的值是不合适的


在我上面的程序中,函数式编程是否允许更改名为
count
的局部作用域对象的状态?

我不知道Python,我假设
count
是一个“局部”变量,从外部看不到,每次调用
hailstone
都会得到自己的
count
实例。如果是这样的话,那么,正如@jornsharpe所解释的,您对
计数所做的事情是无关紧要的

但是,请注意,您的代码是不必要的冗长。为什么不简单地:

if n > 1:
    if n % 2 == 0:
        return 1 + hailstone(n/2)
    else:
        return 1 + hailstone(n*3+1)
else:
    return 1

事实证明,根本不需要该变量,更不用说需要对其进行更新。

您的函数在函数级别没有副作用(除了打印
之外)。这是称为泛函的必要条件,但不是充分条件。函数程序由一个大表达式组成。您的示例是函数级别的表达式,在函数体中穿插命令语句。不带
else
if
是语句,变量重新分配也是语句


这并不是说没有副作用的命令式函数并不比有副作用的命令式函数好。您的示例当然有一些优点,即使它不被认为是纯功能性的。

此程序会发生变异
x

x = 2
x = x * 3
x = x + 4
return x
在函数式编程中,不使用变异。您的代码应该精确地定义每个变量一次:

x1 = 2
x2 = x1 * 3
x3 = x2 + 4
return x3
编译器可能会为x1、x2和x3分配相同的内存位置,并像原始程序一样在适当的位置进行变异。然而,这是一个实现细节,不应该很重要

与以前的顺序程序不同,您可以将新程序视为一个方程组,并以任意顺序读取它。在这种情况下,由于数据依赖性,计算仍然必须从上到下进行,但通常不必这样做

通过使用函数,可以完全去掉“=”符号。要去掉“x1=2”,请按x1参数化其余行,并将2传递给函数:

(function(x1) {
    x2 = x1 * 3
    x3 = x2 + 4
    return x3
})(2)
并继续此过程以删除“x2=x1*3”和“x3=x2*4”

有时,在循环中指定一个变量来累加某些内容(例如,为a:sum+=x中的x在数组
中添加项)。在这种情况下,您可以重写程序以使用诸如“sum”、“reduce”、“map”、“filter”等函数,而不是重复赋值,这些函数是循环的高级抽象



我在撒谎。在一个纯函数程序中,有可能存在局部可变状态,只要可变性不“泄漏”到范围之外。在Haskell中,有一个名为“ST”的库用于此目的。它嵌入了一个带有命令“create variable”、“read variable”、“write variable”的小型命令式语言,如果您的程序没有泄漏可变变量,您可以在纯函数中检索其结果。但是,使用(请参阅)更为笨拙,而且没有像在命令式语言中使用赋值那样多。

函数式编程没有明确的定义。然而,它通常意味着没有副作用,或者至少是最小化副作用——有时人们谈论纯函数式编程来强调其完全没有副作用。但什么是副作用

一个常见的定义是,副作用是任何破坏引用透明度的东西。引用透明性反过来可以用各种方式定义,但也许最有启发性的定义是,评估的顺序应该是无关的。也就是说,如果只需替换定义而不改变程序的结果,就可以按任何顺序简化其任何子表达式,则程序是引用透明(或纯)的。特别是,您始终可以使用其(唯一!)定义替换变量

显然,对可变变量的赋值打破了这种情况,因此必须将其视为副作用——即使它只是局部的。顺便说一句,同样是一份打印声明


有一些方法可以在不破坏引用透明性的情况下获得可变状态或IO。这是单子的神秘概念。但是我不会在这里讨论这个问题。

您的代码没有副作用。无法从函数外部判断它是否使用
count
实现;这是一个纯粹的局部变量。此外,Python中的整数是不可变的;
count
引用的对象永远不会更改,增广赋值会引用一个同名的新对象。@jonrsharpe是的,每当您修改该对象的值(
>a=2>>a+=2
)时,python都会创建新的
int
类型对象。我如何定义可变性?是对象的wrt状态更改还是对象的wrt标识更改?@overexchange参见例如@overexchange这不是一个适当的讨论;我不会在评论中向您解释Python的整个对象模型。做些调查!关系
(function(x1) {
    x2 = x1 * 3
    x3 = x2 + 4
    return x3
})(2)