On Thursday, April 9, 2015 at 3:33:29 PM UTC+2, Daan Huybrechs wrote:
>
> Trying to grasp staged functions in Julia 0.4, I found the new 
> documentation <https://github.com/JuliaLang/julia/pull/10673> and this 
> issue <https://github.com/JuliaLang/julia/pull/7474> very helpful. (Note 
> from the issue that the syntax may still change from `stagedfunction` to, 
> perhaps, `@generated function`).
>
> There are tons of introductory examples of how to do compile-time 
> factorials in languages with metaprogramming and I was wondering how to do 
> this in Julia. I've learned by doing this and my best attempt so far is 
> (using another 0.4 feature with Val{T}) :
>
> stagedfunction fac{N}(::Type{Val{N}})
>     N == 1 ? z = 1 : z = N*fac(Val{N-1});
>     println(z);
>     :($z)
> end
>
> I did not see a way to get rid of the argument in the function above, 
> since Julia does not allow the definition of fac{N}() without N being used 
> in the signature, so the result looks a bit awkward. I also failed to 
> achieve the same result using macros, as it seems macros can't be 
> recursive, but maybe I just missed it (and I wanted to use stagedfunctions 
> anyway). Any better ideas?
>
> The println in the example is helpful to see what is actually happening:
>
> julia> fac(Val{4})
> 1
> 2
> 6
> 24
> 24
>
> julia> fac(Val{7})
> 120
> 720
> 5040
> 5040
>
> julia> fac(Val{7})
> 5040
>
> julia> @code_native fac(Val{6})
>         .text
> Filename: no file
> Source line: 0
>         pushq   %rbp
>         movq    %rsp, %rbp
>         movl    $720, %eax              # imm = 0x2D0
> Source line: 0
>         popq    %rbp
>         ret
>
>
> The cool thing here is that the function works as if Julia automagically 
> caches the previous result. The first computation of 7! just continues 
> where 4! left off and the next computation is instant, as the instructions 
> for Val{6} also show. Can staged functions be used (or abused) to cache 
> one-time computational results during a session?
>


When you ran fac(Val{4}) you compiled fac(Val{4}), fac(Val{3}), fac(Val{2}) 
and fac(Val{1}). These are all folded down to just returning a constant. 
When you later run
 fac(Val{7}) and it iterates down to  fac(Val{4}), this method is already 
in the method cache so it is just runs and returns the constant. The 
println only happens during compilation.
 

>
> A simpler alternative I was hoping for is the following:
>
> fac{N}(::Type{Val{N}}) = N*fac(Val{N-1})
> fac(::Val{1}) = 1
>
> but in this case the compiler does not seem to inline the result of, say, 
> fac(Val{3}) in functions that use it.
>
>

Reply via email to