3

我想在程序的不同部分多次调用类似rand((0, 1), N)(之前分配了一些整数)的东西(我将来可能会将所有出现的情况更改为,例如,或)。如何创建一个变量,每当它被引用时,它都会评估这个函数?Nrand((-1, 1), N)randn(N)

我不想只写这样rand_thing = rand((0, 1), N);的东西,因为那时随机值每次都相同,这是不希望的。

当然,我可以在我想写的时候定义rand_func = rand((0, 1), N);和调用. 我也可以做一些涉及到的事情,然后在我想写的时候打电话。但是,有没有办法我可以获得这个功能并且只写来生成我的随机数?rand_func()rand((0, 1), N)evalrand_ex = :(rand((0, 1), N));eval(rand_ex)rand((0, 1), N)rand_thing

这是一个具体的例子,它是一个更大的问题的一部分,即是否有东西可以直接完成Mathematica中SetDelayed( ) 的功能。:=如果我这样做rand_thing := RandomReal[];而不是thing = RandomReal[];在 Mathematica 中,那么每次我写rand_thing我都会得到一个新的随机数。(在 Mathematica 中,我不会使用下划线作为变量名,但无论如何。)

如果我所描述的内容是不可能的,那么对于为什么SetDelayed在 Mathematica 中可能但在 Julia 中没有类似的东西的一些见解将不胜感激。这是语言的根本区别吗?或者这是不同约定的问题?或者,也许 Julia 可以很容易地拥有一个延迟集合运算符,但到目前为止它还不是语言语法的一部分?(如果是这样,实现会是什么样子?)或者别的什么?

4

1 回答 1

4

(首先让我说,我对 Wolfram 语言的唯一了解是它基于术语重写。)

一个变量,每当它被引用时,都会评估这个函数

被称为...一个函数,正如您正确观察到的那样。

rand_thing() = rand((0, 1), N)

不,rand_thing除了返回该符号的值之外,没有其他方法可以对符号 进行评估。只有改变评估的工作方式,你才能拥有它。

现在,在 Mathematica 中,评估的工作方式确实不同。在那里你基本上有一个重写系统。默认情况下,评估的工作方式类似——“如果你看到一个 name x,查找它的x值并用该值替换,然后继续评估”。

{} (x = 2; x) 
  ~> {x = 2} x   # update environment
  ~> {x = 2} 2   # replace x

(这是伪符号,我在其中使用{}随身携带的环境,~>代表“评估到”。)

但如果x由 定义SetDelayed,则更像是“查找 的定义x,将其替换为定义,然后继续评估”:

{N = 42} (x := rand(N); x)
  ~> {N = 42, x = :(rand(N))} x                # update environment
  ~> {N = 42, x = :(rand(N))} rand(N)          # replace x
  ~> {N = 42, x = :(rand(N))} rand(42)         # replace N
  ~> {N = 42, x = :(rand(N))} [0.2342343, ...] # evaluate call

在 Julia 中更改评估的唯一方法是使用。但这并不比函数调用短;你必须写一些类似的东西

@undelay x .+ 1

扩展到

(rand(N)) .+ 1

但我看不出有任何有利的理由。另外,您必须弄清楚哪些值是延迟的,哪些是正常值,这会使事情复杂化。

你可以组成像这样的语法

@delayed let x = rand(N)
    x .+ 1
end

不过,但是您必须自己注意保留正确的范围界定行为,对此我不知道一个简单的解决方案。(甚至

@delayable begin
    x := rand(N)
    x .+ 1
end

可以作为宏,但更麻烦。)


请注意,有一个称为thunk的概念,它朝着您想要的方向发展——但它是一种数据结构,是对函数的语义抽象,不会使语法更容易。

于 2020-05-24T08:57:04.217 回答