在Mathematica中,如果你想要一个函数来记住它的值,那么它在语法上是非常轻松的。例如,这是标准示例 - 斐波那契:
fib[1] = 1
fib[2] = 1
fib[n_]:= fib[n] = fib[n-1] + fib[n-2]
在朱莉娅有一些语法上令人愉快的方式吗?它使其更多涉及的部分原因是类型系统 - 这是一个单独的无类型arg的实现:
function memoizeany(func)
thedict = Dict()
return (a)-> memoizeanyaux(a, func, thedict)
end
function memoizeanyaux(a, func, thedict)
if haskey(thedict, a)
return thedict[a]
end
res = func(a)
thedict[a] =res
return res
end
为每种类型的签名执行此操作似乎有点痛苦,并且大概是朱莉娅这样做的方法是使用@memoize
宏,但实际上并没有回答这个问题。当然这已经出现了。
当我需要使用使用持久性内存的函数时,我只需创建struct
s并重载call
表示法以使它们成为仿函数。对于您提供的示例,我将把Fibonacci序列写为
struct MyFib{T<:Real}
n::Vector{T}
function (::Type{MyFib})(::Type{T} = Int) where T
new{T}([0, 1])
end
function (m::MyFib{T})() where T
result = sum(m.n)
m.n .= [result, m.n[1]]
return result
end
end
m = MyFib()
for n in 1:10
@show n, m()
end
这种使用struct
s的方式足以让我在计算中封装我需要的任何东西。另外,因为它是使用参数T
严格键入的,所以它也很有效。
然后,对于上面的例子,你也可以使用一些参数函数和函数递归,这有望受益于v0.7
中的整数常量传播,以获得与C++
中的模板化对应物一样有效:
myfib(::Val{0}) = 0
myfib(::Val{1}) = 1
function myfib(::Val{N})::Int where N
return myfib(Val{N-1}()) + myfib(Val{N-2}())
end
# or, as a single liner, as per crstnbr's comment,
myfib(::Val{N}) where N = myfib(Val{N-1}()) + myfib(Val{N-2}())
# and, with some syntactic sugar, thanks to SalchiPapa,
myfib(n::Int) = myfib(Val{n}())
for n in 1:10
@show n, myfib(n)
end
我认为与Mathematica版本相比,后者对你的例子更友好。但它不像前者那样通用,你会对编译器施加一些压力,因为它是一种编译时技术。