在表达式

时间:2017-05-17 05:35:48

标签: metaprogramming julia

我对朱莉娅来说相当新,所以对我可能有的语言的任何误解表示道歉。我最近大部分时间都在使用Python,并且大量使用了SymPy及其代码生成功能,看起来Julia的元编程功能是为了完全按我喜欢的方式编写代码而构建的。

特别是,我想在一组较小的构建块中构建Julia中的块矩阵,其间有一些不同的操作。出于调试目的,并且因为在其他计算中使用了各种中间矩阵,我想将它们保存为包含变量的表达式,这样我就可以快速循环并测试不同的不同输入,而无需将所有内容包装在函数中。

现在,对于一个最小的案例研究,我说有两个表达式mat1 = :amat2 = :b,我想要组合起来形成一个新的第三个表达式:

mat3 = :($mat1 + $mat2)

上述方法正常直到我修改mat1mat2,在这种情况下,我必须重新评估mat3才能反映此更新。我认为,这是因为$mat1 + $mat2没有通过引用传递mat1mat2,而是在评估该行时插入内部的表达式。我想要实现的行为是mat1mat2在我调用eval(mat3)之前不会插入,最好是最小的样板。

是否有可能以方便的语法实现这一目标?

1 个答案:

答案 0 :(得分:9)

mat3将反映mat1mat2变异,但不会反映mat1的{​​em>重新绑定和{ {1}}。了解突变和重新绑定之间的区别非常重要。

突变

修改对象的数据时发生突变。请注意,这不会影响任何名称,只会影响对象。这可以通过多种方式表现出来,包括mat2等函数和具有复杂左侧的赋值语法,如push!

例如,以下所有都是变异的例子:

A[1] = 5

名称A未更改; A仍然指向同一个对象。 A = [1, 2, 3] A[1] = 4 表示的对象已被修改。

A

名称A未更改; A仍然指向同一个对象。 A = :(f(x)) A.args[1] = :g 表示的对象已被修改。

A

名称mat1 = :(f(x)) mat2 = :(f(y)) mat3 = :($mat1 + $mat2) mat1.args[1] = :g 未更改;它仍然指向同一个对象。该对象已被修改。 mat1也引用了同一个对象,并且因为它已被修改,它将反映这些更改。实际上,现在mat3包含mat3

重绑定

(也称为作业)

没有修改对象数据但是名称的目标更改为其他对象的目标时,会发生重新绑定。这由一个简单的:(g(x) + f(y))赋值表示,左侧是反弹的东西。

=

此处x = 2 x = 3 正在从对象x反弹到对象2。我们不是更改对象3。实际上,因为2不可变的对象,所以不允许改变对象2。相反,2的可观察值发生变化的原因是因为它现在引用了另一个对象:x

3

再一次,我们不是改变向量A = [1, 2, 3] A = [4, 2, 3] ;我们正在创建一个新的向量,现在A引用了这个新向量。区分突变和重​​新绑定很重要。同样,变异作用于对象,重新绑定作用于名称

A

请注意,简单赋值不会 mutate mat1 = :x mat2 = :y mat3 = :($mat1 + $mat2) mat1 = :z 引用的对象:x;它只是将mat1重新绑定到不同的对象mat1。这意味着包含对象:z的{​​{1}}不会受到影响。

请注意,mat3不可变类型,因此您无法对其进行变更。因此,不可能做你提出的建议。

做出你提出的建议的更好方法是使用函数而不是单个表达式。可以多次调用函数,生成不同的对象。

:x