To answer your last question first, the type syntax of All
doesn't permit binding multiple dotted variables at once, because it wouldn't be clear how to instantiate them. This is the same reason you can't have multiple rest parameters in the same function.
As to lift
, I think the type you want is:
(: lift (All (C A ...)
(All (B ...)
((B ... B -> C)
->
((A ... A -> B) ... B
->
(A ... A -> C))))))
And then the function goes through with one annotation:
(define (((lift fn) . gs) . args)
(apply fn (map
(λ: ([g : (A ... A -> B)])
(apply g args))
gs)))
Using this function requires some explicit annotation because of the nested foralls; here are your test cases:
(define add ((inst (inst lift Number Number) Number Number) +))
(define add2 ((inst (inst lift Number Number Number Number Number Number)
Number Number)
+))
(define sum-of-sin-and-cos (add sin cos))
(sum-of-sin-and-cos 5) ; is equivalent to (+ (sin 5) (cos 5))
(define sum-of-multiplication-and-division (add2 * /))
(sum-of-multiplication-and-division 1 2 3 4 5)
Note that I had to create a separate binding for add2
because they're used at different types.