To my knowledge, one of the situations where the third argument of Compile
is required is when your compiled code needs to make a MainEvaluate
call. Often, the situation is the other way around: you have code and you try to compile it down completely, so that no MainEvaluate
call is necessary. Honestly, most of the questions about Compile
here deal to some extend with this issue.
What is, when it is out of question that some part of your code has to be run by the kernel and cannot be compiled under no circumstances? Then the task is to build this into your compiled code, so that it works and the compiler can determine the type of your external call. Let's assume a simple function which collects some prime numbers:
primes[n_] := Last[Last[Reap[Table[If[PrimeQ[i], Sow[i]], {i, n}]]]]
and now you want to have a compiled function which multiplies such a list with an integer giving you an integer list back. First, you can play around with this snipped
Compile[{{n, _Integer}}, Module[{a = 2},
a*Last[Last[Reap[Table[If[PrimeQ[i], Sow[i]], {i, n}]]]]
]
]
but this is not fun and Reap
and Sow
are bad for compiling anyway. The solution is the third argument to Compile
:
fc = Compile[{{n, _Integer}}, Module[{a = 2},
a*primes[n]
], {{primes[_], _Integer, 1}}
]
because you can get a working and readable version of your function. Now assume that you have a compiled function where you need the result of NMinimize
or some similar (uncompilable) function. This is your use-case.
As for your initial problem with y
and AppendTo
: The type of local variables can be coerced in other ways. For instance, if you want to say that y
should be an integer list, then initialize it with Most[{1}]
which gives you an empty list, but the compiler saw that you want an integer list :-)
cfu = Compile[{}, Module[{y = Most[{1}]}, AppendTo[y, 1]]];
cfu[]
(* {1} *)
y
goes out of scope beforeCompile
can use that argument. The way to solve this problem for local variables is to initialize them insideModule
declaration to correct types, and then possibly redefine in the body ofModule
to the values you really need, like e.g.cfu = Compile[{}, Module[{y = Rest[{0}]}, AppendTo[y, 1]]]
. $\endgroup$Compile
but find the third argument to be a by mysterious. $\endgroup$Compile
doesn't use ordinary scoping rules (for example,Module
,Block
,With
are all treated exactly the same), so AIUI your explanation isn't correct. I think the real reason is that the third argument only applies to values that are obtained via calls out of the VM--it is a type hint, rather than a declaration. $\endgroup$Compile
not using the standard scoping rules, and you may be right, although I seem to remember that there were cases which actually led me to this conclusion. If / when I am able to dig out some examples, I will get back. $\endgroup$Rest
/Most
), normally all the types are correctly inferred. If not, and where there is no suitable hack, I've usually found the the situation to be hopeless, sometimes even resulting in a kernel crash where types do not match what was inferred. $\endgroup$