Hi,
I would like to call a function with parameters from a tuple. It is called apply in Closure, and do.call in R. This is what I have so far:
# example functions:
proc distSquare(x: int, y: int): int = x*x + y*y
proc distSquare(x: int, y: int, z: int): int = x*x + y*y + z*z
# the call functions:
proc call[T,S,X](f: proc(a: T, b: S): X, param: (T, S)): X =
result = f(param[0], param[1])
proc call[T,S,U,X](f: proc(a: T, b: S, c: U): X, param: (T, S, U)): X =
result = f(param[0], param[1], param[2])
# tests:
var twoParams = (11, 1)
echo call(distSquare, twoParams) # prints 122
var threeParams = (11, 1, 100)
echo call(distSquare, threeParams) # prints 10122
My questions are:
2. I can't use a function which has more than one implementation with the same number of parameters. For example if I define
proc distSquare(x: string, y: string): string = x & " " & y
as well, then echo call(distSquare, twoParams) fails to compile. If I change the parameter order in call, then from the variable twoParams it can find out which to use, otherwise not. Would it be possible to make the template matching algorithm smarter?
Motivation:
assert mapIt(@[1,2,3], (it, 10*it)).map(call(f)) == @[f(1,10), f(2,20), f(3,30)]
I have a macro that implements curry() https://gist.github.com/fowlmouth/9b9010397ad5fe4b9872#file-xcurry-nim works like this
proc f (a,b,c,d:int): int =
a*b+c/d
let f2 = curry(f, 1, 2)
# returns this function
# proc(c,d:int):int = f(1,2,c,d)
# compile-time type info is used to look up the parameter types of f so that the proper function is returned
assert f2(3,4) == curry(f2,3)(4)
if the function f was overloaded, we can use a slightly more wordy syntax to specify which f should be used, this example is for strutils.repeat which has 2 overloads
import strutils
let f = curry((proc(c:char; num:int):string)repeat, 'h')
assert f(3) == "hhh"
more examples of macros.getType here: https://gist.github.com/fowlmouth/3c74409c30533bb0a5b4 its a very powerful new feature ^ feel free to take these, copy them, finish them, whatever. it looks like curry() may need more coverage in its case statement at line 16@filwit: Thank you for your answer. I'm familiar with varargs, even for macros. I had problems with the function call.
@fowl: It is amazing! I'll use this, and implement the call based on this!
Slightly different topic: I can copy a function if there is only one of them, or it is unique by its type:
proc f(x: int, y: int): int = x+y
proc f(x: int, y: string): string = $x & y
var g: proc(q: int, w: int): int = f
echo g(10, 11) # prints 21
I could imagine a function copy which copies all the instances, e.g.:
proc f(x: int, y: int): int = x+y
proc f(x: int, y: string): string = $x & y
var g = f # currently compile error
echo g(10, 11) # could print 21
echo g(10, "11") # could print "1011"
What do you think? Would it be possible to implement? There is no real advantage of this particular example, but please imagine something like:
proc f(x: int, y: int): int = x+y
proc f(x: int, y: string): string = $x & y
var first = (10, 11)
var second = (10, "11")
call(f, first) # not yet implemented
call(f, second)
var g = f # currently compile error
call(f, first)
call(f, second)
Or with curry:
proc f(x: int, y: int): int = x+y
proc f(x: int, y: string): string = $x & y
var g = curry(f, 10) # currently compile error
echo g(11) # could print 21
echo g("11") # could print "1011"
Please give me feedback. Am I the only one who would like this?
Thanks, Peter
Please give me feedback. Am I the only one who would like this?
I dunno if I like it or not but more complexity in the already complex type system is not desirable at all.