Closed okeuday closed 3 years ago
I am effectively suggesting I should be able to make the $CLOUDI.subscribe
function call (https://github.com/CloudI/CloudI/blob/7e0adae04f75900acdef8db5c213a893c930b68d/src/api/ats/v2/cloudi.dats#L1109-L1117) look like:
implement {s}
$CLOUDI.subscribe
(api,
suffix,
f) = let
val INSTANCE(@{api_c_ptr = (_, _ | api_c), ...}) = api
fn
f_wrapper
(request_type: $CLOUDI.request_type,
name_c: ptr,
pattern_c: ptr,
request_info_c: ptr,
request_info_size_c: uint32,
request_c: ptr,
request_size_c: uint32,
timeout_c: uint32,
priority_c: int8,
trans_id_c: ptr,
pid_c: ptr,
pid_size_c: uint32,
state_c: ptr,
f_api_c: ptr):<fun1>
void =
$CLOUDI.callback_attach<s>(f,
request_type, name_c, pattern_c,
request_info_c, request_info_size_c,
request_c, request_size_c,
timeout_c, priority_c, trans_id_c,
pid_c, pid_size_c, state_c, f_api_c)
val f_c: $CLOUDI.c_callback = f_wrapper
in
result_value_unit(c_subscribe(api_c, string2ptr(suffix), f_c), api)
end
The source code above does compile because the function is a template but fails once it gets to the tests/count/ats/v2/main.dats
file.
Yes, you can create an envless function inside another function.
But f_wrapper cannot be an envless function because its body contains 'f', which is not an argument of f_wrapper itself.
Here is a way to "fix" the issue.
HX-2021-06-13: The following code causes the "envless" problem you encountered:
fun apply ( f0 : int -> int): int = f0(0)
fun foo(x: int): int = let fun bar(y:int): int = x + y // bar is not envless! in apply(bar) end
############
HX-2021-06-13: The 'foo' can be turned into a template to circumvent the "envless" problem:
extern fun{} foo$x(): int
fun{} foo(): int = let // fun bar(y:int): int = foo$x<>() + y // in apply(bar) end
implement main0() = { // implement foo$x<>() = 50 // val foo50 = foo() val ( ) = println!("foo50 = ", foo50) }
@githwxi Thank you for describing this solution. I changed the source code to using this approach and avoided the envless problem.
Isn't it possible to allow the creation of an ordinary non-closure function when the function is created using constants from the environment (i.e., when creating an ATS function in another ATS function)? When I attempt to do this, I get
ATSERRORnotenvless
in the C source code, though I am only passing an ATS function pointer value into the new function.I have tried to do this within a function template, which doesn't improve the situation but appears to match what could work because it could be possible to create a unique non-closure function for each call to the function template (that is what I am attempting to do). Allowing this to work is helpful when considering the alternative, which requires manually creating a separate function for each call (resulting in more lines of source code).
I have been looking at this problem to simplify the
$CLOUDI.subscribe
function call in source code like https://github.com/CloudI/CloudI/blob/7e0adae04f75900acdef8db5c213a893c930b68d/src/tests/count/ats/v2/main.dats#L97 (to avoid the need to define therequest
function explicitly in that file). This situation really relates to using an ATS function pointer in C source code which may not be common (my goal was to do this without modifying the C source code, so I wasn't considering having a closure or an env parameter).