有人知道茱莉亚为何选择无法修改作为输入给出的参数的功能设计的原因吗?无论如何,这都需要通过以荒谬的单元素表的形式表示这些数据来经历一个非常人为的过程。
具有相同局限性的Ada在2012年的重新设计中放弃了它,获得了用户的极大满意。一个小的关键字(例如Ada中的关键字)很可能表明需要在输出端保留对参数的修改。
答案 0 :(得分:2)
根据我在Julia中的经验,了解值和绑定之间的区别很有用。
Julia中的每个值在内存中都有一个具体的类型和位置。价值可以是可变的或不变的。特别是,当您定义自己的复合类型时,可以决定该类型的对象是可变的(mutable struct
)还是不可变的(struct
)。
当然,Julia具有内置类型,其中一些是可变的(例如数组),而其他则是不可变的(例如数字,字符串)。当然,它们之间存在设计权衡。在我看来,不变值的两个主要优点是:
但是,特别是,如果要将不可变值包装在可变包装器中,一种标准方法是使用Ref
,如下所示:
julia> x = Ref(1)
Base.RefValue{Int64}(1)
julia> x[]
1
julia> x[] = 10
10
julia> x
Base.RefValue{Int64}(10)
julia> x[]
10
您可以将这些值传递给函数并在内部对其进行修改。当然Ref
引入了不同的类型,因此方法的实现必须有所不同。
变量是绑定到值的名称。通常,除了某些特殊情况,例如:
A
中模块B
的变量; 您可以重新绑定变量以指向所需的任何值。在大多数情况下,重新绑定是使用=
或某些特殊构造(例如,在for
,let
或catch
语句中执行的)。
现在-切入点-函数将传递一个值,而不是绑定值。您可以修改函数参数的绑定(换句话说:您可以重新绑定参数指向的值),但是此参数是一个新鲜变量,其作用域位于函数内部。
例如,如果我们要打这样的电话:
x = 10
f(x)
更改变量x
的绑定是不可能的,因为f
甚至都不知道x
的存在。它只会通过其值。特别是-正如我在上文中提到的-添加这样的功能将破坏规则,即模块A
无法重新绑定模块B
中的变量,因为f
可能是这样。在与定义x
的模块不同的模块中定义。
实际上,根据我的经验,使用此功能很容易:
x,y,z = f(x,y,z)
,其中可以定义f
,例如为f(x,y,z) = 2x,3y,4z
; macro plusone(x) return esc(:($x = $x+1)) end
并且现在写y=100; @plusone(y)
将更改y
的绑定; Ref
(或任何其他可变包装器-如您在问题中所指出的那样)。答案 1 :(得分:0)
“有人知道茱莉亚为何选择无法修改作为输入给出的参数的功能设计的原因吗?” Schemer询问
您的问题是错误的,因为您假设错误的事情。
当您将事物传递给函数时,这些事物通常是值而不是变量。
例如:
function double(x::Int64)
2 * x
end
现在使用调用它会发生什么情况
double(4)
修改参数x的功能的意义是什么,毫无意义。此外,该函数不知道如何调用它。
此外, Julia旨在提高速度。
修改参数的函数将难以优化,因为它会引起副作用。副作用是过程/函数在其范围之外更改对象/事物时。
如果函数未修改属于其调用参数的变量,那么您可以放心知道。
以上三个因素导致功能语言快速运行和非功能语言缓慢运行。
此外,当您进入并行编程或多线程编程时,如果您(程序员)不了解该变量,则绝对不要更改其值。
“如何用建议的宏实现函数F(x),该函数返回布尔值并通过c:= c + 1修改c。F可用于以下Ada代码:c:= 0; While F(c)Loop ... End Loop;“ Schemer询问
我会写
function F(x)
boolean_result = perform_some_logic()
return (boolean_result,x+1)
end
flag = true
c = 0
(flag,c) = F(c)
while flag
do_stuff()
(flag,c) = F(c)
end
“不幸的是,没有,因为,我应该说,当F返回值False时,c必须再次取值0(随着Loop的生存,c会增加,并且在它死时返回0)。”
那我要写
function F(x)
boolean_result = perform_some_logic()
if boolean_result == true
return (true,x+1)
else
return (false,0)
end
end
flag = true
c = 0
(flag,c) = F(c)
while flag
do_stuff()
(flag,c) = F(c)
end