As a follow up to Why can't generic function templates use fnx to ensure they are tail-recursive?, and after reading Compiler Friendly Tail Recursion + Tail Recursion Checking in ATS, I wanted to see if i could ensure my function either got tail-call optimized, or failed to compile. This is the function:
fun {a:t@ype} repeat {n:nat} .<n>.
( x: a
, t: int n
, f: a -> a
) : a =
if t = 0 then x
else repeat (f x, t - 1, f)
So first I made it a trivial mutually recursive function, like so:
fnx {a:t@ype} repeat1 {n:nat} .<n>.
( x: a
, t: int n
, f: a -> a
) : a =
if t = 0 then x
else repeat1 (f x, t - 1, f)
and {a:t@ype} repeat2 {n:nat} .<>.
( x: a
, t: int n
, f: a -> a
) : a = repeat1 (x, t, f)
But that doesn't compile, it seems like it doesn't like the generic type arguments. So I put the definition inside a third parent function, which has the generic argument and just calls into the mutual recursive pair.
fun {a:t@ype} repeat {n:nat} .<n>.
( x: a
, t: int n
, f: a -> a
) : a =
let
fnx repeat1 {n:nat} .<n>.
( x: a
, t: int n
, f: a -> a
) : a =
if t = 0 then x
else repeat1 (f x, t - 1, f)
and repeat2 {n:nat} .<>.
( x: a
, t: int n
, f: a -> a
) : a = repeat1 (x, t, f)
in
repeat1 (x, t, f)
end
Viola, it compiles! But then I tried calling repeat2 instead of repeat1 in the last line, like so:
fun {a:t@ype} repeat {n:nat} .<n>.
//snip...
in
repeat2 (x, t, f)
end
And this fails to compile, with error:
the dynamic identifier [repeat2] is unrecognized.
Hence, the question in the title.
When you use 'fnx' to define mutually recursive functions, only the first defined function is available for subsequent use.