朱莉娅备忘录

问题描述 投票:4回答:1

在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宏,但实际上并没有回答这个问题。当然这已经出现了。

julia wolfram-mathematica dynamic-programming
1个回答
6
投票

当我需要使用使用持久性内存的函数时,我只需创建structs并重载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

这种使用structs的方式足以让我在计算中封装我需要的任何东西。另外,因为它是使用参数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版本相比,后者对你的例子更友好。但它不像前者那样通用,你会对编译器施加一些压力,因为它是一种编译时技术。

© www.soinside.com 2019 - 2024. All rights reserved.