Stack-allocated closures

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.

Hongwei,

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.

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.

The reason that you see the following style of implementation
is due to a difficulty in handling template parameters that are
dependent types:

implement(a2)
list_tabulate$fopr (n) = $UN.castvwtp0{a2}(f(n))

a2 and a are indeed the same. The way in which
list_tabulate$fopr is implemented guarantees that
this implementation will be called by the instance
list_tabulate (n) (as a2 is a variable that can
match any template parameter). This is a bit technical,
and I will try to make the point clear in my
ATS-Intro book.On Tuesday, February 25, 2014 11:53:57 PM UTC-5, Artyom Shalkhakov wrote:

The type of list_tabulate_clo is:

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]

It’s supposedly unsafe to do a cast, yet the file is littered with unsafe
casts all over the place. Makes me a bit nervous.

Also, note that list_tabulate$fopr is defined such that it returns some
element of some vt@ype. Shouldn’t a2 and a be the same type?

On Saturday, February 22, 2014 11:59:41 AM UTC+6, gmhwxi wrote:

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.

The type of list_tabulate_clo is:

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]

It’s supposedly unsafe to do a cast, yet the file is littered with unsafe
casts all over the place. Makes me a bit nervous.

Also, note that list_tabulate$fopr is defined such that it returns some
element of some vt@ype. Shouldn’t a2 and a be the same type?On Saturday, February 22, 2014 11:59:41 AM UTC+6, gmhwxi wrote:

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.