How to define a function in Scheme / Racket that returns functions of particular arities?
Currently I have in my code the following:
(define (get-function n)
(cond
[(= n 1) (lambda (a) a)]
[(= n 2) (lambda (a b) (+ a b))]
[(= n 3) (lambda (a b c) (+ a b c))]
; and so on
))
Of course arity of a function it returns is n:
(procedure-arity (get-function 3)) ; returns 3
Please don't mind "+", in my program it's more complicated than a fold of "+". However, the structure of that function could be defined recursively as well; similar to:
(define (get-function-variadic n)
(lambda arguments
(if (empty? arguments) 0
(+ (car arguments)
(apply (get-function-variadic (sub1 n)) (cdr arguments))))))
But then it returns variadic functions:
(procedure-arity (get-function-variadic 3)) ; returns #(struct:arity-at-least 0)
so that all of these work just as the normal Scheme's variadic "+":
((get-function-variadic 3) 1 2 3)
((get-function-variadic 3) 1 2)
((get-function-variadic 3) 1 2 3 4)
In fact I want only the first one to return a result, while others should return an error "wrong number of arguments". Additionally, in other parts of a program I rely on arity of the functions generated. So, a variadic function doesn't suit me (even if it checks the length of "arguments"). I need a set of functions of different integer arities returned by (get-function n). Is it possible to define in Scheme / Racket?
This feels like an XY problem, so I don't know if this well help you, but:
As @Renzo commented, if you do not need to do this at run time, it might be cleaner and faster to use a macro to do it at compile time.
I don't understand why you need a get-function-variadic
that returns functions that are... not variadic. However I suppose you could use procedure-reduce-arity
to get the expected results in your examples:
#lang racket
(define (-get-function-variadic n)
(lambda arguments
(if (empty? arguments) 0
(+ (car arguments)
(apply (get-function-variadic (sub1 n)) (cdr arguments))))))
(define (get-function-variadic n)
(procedure-reduce-arity (-get-function-variadic n) n))
(require rackunit)
(check-exn exn:fail:contract:arity? (λ () ((get-function-variadic 3) 1 2)))
(check-equal? ((get-function-variadic 3) 1 2 3) 6)
(check-exn exn:fail:contract:arity? (λ () ((get-function-variadic 3) 1 2 3 4)))