This code to "uncurry" a two parameter function is almost certainly incorrect Nim, but on macOS with the devel compiler it causes a SIGSEGV: Illegal storage access. (Attempt to read from nil?) error.
func uncurry*[T, U, V](fn: proc (x: T, y: U): V {.nimcall}): (proc (xs: (T, U)): V {.nimcall.}) =
proc foo(xs: (T, U)): V {.nimcall.} = fn(xs[0], xs[1])
func add(a: int, b: int): int = a + b
echo (uncurry(add))((1,2))
If any can confirm this is a compiler issue I'll open a GitHub issue.
$ nim --version
Nim Compiler Version 1.5.1 [MacOSX: arm64]
Compiled at 2021-07-22
Copyright (c) 2006-2021 by Andreas Rumpf
git hash: 58e27ebd4a16ca9f2ba24826d7162384d5321101
active boot switches: -d:release
Your uncurry function returns nil function pointer and then try to call it. That is why you got SIGSEGV. Your uncurry function just defines local proc foo that is not used.
Don't your compiler print "Hint: 'foo' is declared but not used [XDeclaredButNotUsed]"?
You can try almost latest devel Nim runs on Linux on https://wandbox.org. It seems it builds latest devel once per day. You can check compiler version by adding "-v" to "Compiler options:" text box.
You can also use wandbox from major text editor as long as your PC/smart phone is connected to internet. Please check "Plugin" button on top right of wandbox page.
My intention was to return a proc from uncurry and I've almost certainly gotten that wrong, but I've been guided by syntax errors. If I use:
proc uncurry*[T, U, V](fn: proc (x: T, y: U): V {.nimcall}): (proc (xs: (T, U,)): V {.nimcall.}) =
return proc _(xs: (T, U,)): V {.nimcall.} = fn(xs[0], xs[1])
That is a syntax error: Error: invalid indentation. If I remove the _ to indicate an anonymous proc that is another syntax error:
proc uncurry*[T, U, V](fn: proc (x: T, y: U): V {.nimcall}): (proc (xs: (T, U,)): V {.nimcall.}) =
proc (xs: (T, U,)): V {.nimcall.} = fn(xs[0], xs[1])
I'm still learning Nim and realizing that procs as proc parameters or results are more subtle than I understood.
Calling this a compiler issue is premature I realize.
It looks like wrapping proc parameters and return values in parentheses makes a difference to the error messages produced and that uncurry proc actually being returned and not just created and destroyed inside the uncurry function.
nim check also produces useful error messages with the parentheses in place.
This works totally fine
func uncurry*[T, U, V](fn: proc (x: T, y: U): V {.nimcall}): (proc (xs: (T, U)): V {.closure.}) =
result = (proc (xs: (T, U)): V {.closure.} = fn(xs[0], xs[1]))
func add(a: int, b: int): int = a + b
echo (uncurry(add))((1,2))
This is a sugarized version that also works
import sugar
func uncurry*[T, U, V](fn: (T, U) -> V): ((T, U)) -> V =
result = (xs: (T, U)) => fn(xs[0], xs[1])
func add(a: int, b: int): int = a + b
echo (uncurry(add))((1,2))
Declaring a proc with name is a statement. If it was an expression, we have to declare procedures like discard proc foo() =.
An anonymous proc is an expression and we have to pass it into other procedure, store it to variable or return from a proc. Otherwise, there is no way to call it.
I think if you write an anonymous proc in a proc like this code, Nim compiler pharse it as an proc declaretion. But as identifier is missing, compiler says "Error: identifier expected, but got '('".
proc foo(): proc (x: int) =
proc (x: int) = echo x
If the anonymous proc was enclosed by parenthesis or it used as expression with result = proc (...) or return proc (...), Nim compiler pharse it as anonymous proc.
proc foo(): proc (x: int) =
(proc (x: int) = echo x)
proc bar(): proc (x: int) =
result = proc (x: int) = echo x
proc baz(): proc (x: int) =
return proc (x: int) = echo x
foo()(7)
bar()(77)
baz()(777)