The following function array2list_rev turns an array into a list such that
the sequence represented by the list is the reverse of the sequence
represented by the array:
fun{
a:t@ype
} array2list_rev{n:nat}
(
A: arrayref(a, n), n: int(n)
) : list_vt (a, n) = let
//
var f = lam@ (i: natLt(n)): a => A[n-1-i]
//
in
list_tabulate_clo (n, f)
end // end of [array2list_rev]
Note that the keyword ‘lam@’ is used (instead of lam) to form a
stack-allocated closure.
At run-time, [f] is allocated in the frame of [array2list_rev]; so [f] is
freed once [array2list_rev]
returns.
I’m looking forward to the ATS-Intro write-up on this issue.
Indeed. Lot of casts are unsafe.
My plan is for the community of ats-lang-users to implement
safe versions in the future. Right now, I am just so short of time,
and I feel that I have no other choice but cutting some corners.
This is perfectly understandable.
I can sympathI have been so busy the whole year too.
My plan is for the community of ats-lang-users to implement
safe versions in the future. Right now, I am just so short of time,
and I feel that I have no other choice but cutting some corners.
The reason that you see the following style of implementation
is due to a difficulty in handling template parameters that are
dependent types:
fun{
a:vt0p
} list_tabulate_clo{n:nat}
(n: int n, f: &(natLt(n)) - a): list_vt (a, n)
[f] is a reference to a function with effect; so [f] cannot “escape”
and will be returned back to the caller on return.
Nice to see that it is finally easy to use stack-allocated closures. I’m
still a bit undecided on the implementation strategy you chose:
implement
{a}(tmp)
list_tabulate_clo (n, f) = let
//
val f = $UN.cast{int - a}(addr@f)
//
implement(a2)
list_tabulate$fopr (n) = $UN.castvwtp0{a2}(f(n))
//
in
list_tabulate (n)
end // end of [list_tabulate_clo]