Hello, guys!
Nim can use anonymous procedures in procedures like map(), filter() and other. Is it possible to have procedural return and if yes, how this should be formatted syntactically?
Something like this:
proc pprint(annotation: string): proc(t0: T1): T1 =
# ... some usage of annotation parameter ...
return proc(val) =
val
This example does not compile, but if one change
proc(t0: T1): T1
to
any
then it compiles.
Also, for some reason I have to have forward declaration of the same procedure. Next line does not compile also and I have no idea how to get it compiled.
proc pprint(annotation: string): proc[T1](t0: T1): T1
proc pprint(annotation: string): (proc(t0: T1): T1) =
# ... some usage of annotation parameter ..
Parenthesis help.
proc pprint(ann: string): (proc[T1](t0: T1): T1) =
return proc(val: T1) =
return val
pprint("test")
returner.nim(1, 32) Error: ')' expected
#
proc pprint(ann: string): (proc(t0: T1): T1) =
return proc(val) =
return val
pprint("test")
returner.nim(1, 37) Error: undeclared identifier: 'T1'
proc pprint[T1](ann: string): (proc(t0: T1): T1) =
return proc(val) =
return val
pprint("test")
returner.nim(5, 7) template/generic instantiation from here
returner.nim(1, 13) Error: cannot instantiate: 'T1'
proc pprint(ann: string): (proc(t0: int): int) =
return proc(val: int): int =
return val
pprint("test")
returner.nim(5, 7) Error: value of type 'proc (t0: int): int{.closure.}' has to be discarded; for a function call use ()
Probably this should be done in a different way
Try:
proc pprint[T1](ann: string): (proc(t0: T1): T1) =
return proc(val: T1): T1 =
return val
echo pprint[int]("test")(42)
I have another question.
There is a procedure
proc fold*[T, S](arr: seq[T], init: S, op: proc(acc: S, v: T): S): S =
for x in arr:
init = op(init, x)
return init
How to implement in Nim this function (Javascript):
function applyAllSync(funcs, onAllDone) {
return fold(funcs, (function(onDoneNothing) {
return onDoneNothing;
}), (function(doBefore, func) {
return (function(onDone) {
return doBefore((function() {
return func(onDone);
}));
});
}))(onAllDone)();
};
Well, initially it is not JS. I'm working on our internal compiler's Nim backend.
Original function source (ML-like language):
applyAllSync(funcs: [(() -> void) -> void], onAllDone: () -> void) -> void {
fold(funcs, \onDoneNothing -> onDoneNothing,
\doBefore : (() -> void) -> () -> void, func : (() -> void) -> void -> {
\onDone : () -> void-> {
doBefore(\ -> func(onDone))
}
}
)(onAllDone)();
}
We have first-class citizen functions, so we can treat them as usual objects, which can be returned and used. The syntax here is simple:
() -> void
is like proc(): void
in parameters
\name -> void
is like proc(name: T): void
, used as lambda (T might be changed to any, depends on context),
[]
is an array.
Direct conversion with types gives next Nim code:
proc applyAllSync(funcs: seq[proc(t0: proc(): void): void], onAllDone: proc(): void): void =.
fold(funcs, proc(onDoneNothing: any) =
onDoneNothing, proc(doBefore: (proc(t0: proc(): void): proc(): void), func: (proc(t0: proc(): void): void)) =
proc(onDone: (proc(): void)) =
return doBefore(proc() =
func(onDone)))(onAllDone)()
It doesn't compile, error is
test.nim(3, 77) Error: ')' expected
Position 77 is a letter f in word func at line 3.
I showed Javascript example previously, because it works. I understand JS type system and it was just to show syntax.
Again, my question is 'How syntactically nested lambdas and/or closures can be written?'
Your code does not work because you are using func as identifier, which is a reserved keyword. I demangled it a bit and renamed func to fun:
type
MyProc1 = proc()
MyProc2 = proc(p: MyProc1)
MyProc3 = proc(p: MyProc1): MyProc1
proc applyAllSync(funcs: seq[MyProc2], onAllDone: MyProc1) =
fold(funcs,
proc(onDoneNothing: MyProc1) = onDoneNothing,
proc(doBefore: MyProc3, fun: MyProc2) =
return (proc(onDone: MyProc1): MyProc1 =
return doBefore(proc() =
fun(onDone)
)
)(onAllDone)()
)