Scheme / Racket 中的函数返回特定参数的函数
Function in Scheme / Racket returning functions of particular arities
如何在 Scheme / Racket 中定义一个 return 特定参数的函数?
目前我的代码中有以下内容:
(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
))
当然函数的元数它 returns 是 n:
(procedure-arity (get-function 3)) ; returns 3
请不要介意“+”,在我的程序中它比“+”的折叠更复杂。但是,该函数的结构也可以递归定义;类似于:
(define (get-function-variadic n)
(lambda arguments
(if (empty? arguments) 0
(+ (car arguments)
(apply (get-function-variadic (sub1 n)) (cdr arguments))))))
但是 return 可变参数函数:
(procedure-arity (get-function-variadic 3)) ; returns #(struct:arity-at-least 0)
所以所有这些都像普通 Scheme 的可变参数“+”一样工作:
((get-function-variadic 3) 1 2 3)
((get-function-variadic 3) 1 2)
((get-function-variadic 3) 1 2 3 4)
其实我只希望第一个return一个结果,而其他的应该return一个错误"wrong number of arguments"。此外,在程序的其他部分,我依赖于生成的函数的数量。所以,可变参数函数不适合我(即使它检查 "arguments" 的长度)。我需要一组不同整数元数的函数 return 由 (get-function n) 编辑。是否可以在 Scheme / Racket 中定义?
这感觉像是一个 XY 问题,所以我不知道这是否对您有帮助,但是:
正如@Renzo 评论的那样,如果您不需要在 运行 时执行此操作,那么在编译时使用宏来执行此操作可能会更干净、更快。
我不明白为什么您需要一个 get-function-variadic
的 returns 函数...不是可变的。但是我想你可以使用 procedure-reduce-arity
在你的例子中得到预期的结果:
#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)))
这是一个通过宏的解决方案。我设计它时仍然不知道 (procedure-reduce-arity) 函数(比这个解决方案更通用)。
(define-syntax-rule (variadic->fixed-arity f arguments ...)
(lambda (arguments ...) (f arguments ...)))
(define-for-syntax tails (lambda (l) (if (null? l) (list l) (cons l (tails (cdr l))))))
(define-for-syntax n 10)
(define-syntax (variadic->fixed-arities-up-to-n stx)
(syntax-case stx ()
[(variadic->fixed-arities-up-to-n f)
(let* ([arguments (generate-temporaries (build-list n values))]
[arguments-sets (reverse (tails arguments))])
#`(list
#,@(map (lambda (arguments-set)
#`(variadic->fixed-arity f #,@arguments-set))
arguments-sets)))]))
(define (get-function-of-arity f n)
(define functions-of-fixed-arities (variadic->fixed-arities-up-to-n f))
(if (n . >= . (length functions-of-fixed-arities))
(error "increase number of generated fixed-arities functions")
(list-ref functions-of-fixed-arities n)))
(procedure-arity (get-function-of-arity + 7)) ; returns 7
(apply (get-function-of-arity + 7) (make-list 7 3)) ; returns 21
如何在 Scheme / Racket 中定义一个 return 特定参数的函数?
目前我的代码中有以下内容:
(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
))
当然函数的元数它 returns 是 n:
(procedure-arity (get-function 3)) ; returns 3
请不要介意“+”,在我的程序中它比“+”的折叠更复杂。但是,该函数的结构也可以递归定义;类似于:
(define (get-function-variadic n)
(lambda arguments
(if (empty? arguments) 0
(+ (car arguments)
(apply (get-function-variadic (sub1 n)) (cdr arguments))))))
但是 return 可变参数函数:
(procedure-arity (get-function-variadic 3)) ; returns #(struct:arity-at-least 0)
所以所有这些都像普通 Scheme 的可变参数“+”一样工作:
((get-function-variadic 3) 1 2 3)
((get-function-variadic 3) 1 2)
((get-function-variadic 3) 1 2 3 4)
其实我只希望第一个return一个结果,而其他的应该return一个错误"wrong number of arguments"。此外,在程序的其他部分,我依赖于生成的函数的数量。所以,可变参数函数不适合我(即使它检查 "arguments" 的长度)。我需要一组不同整数元数的函数 return 由 (get-function n) 编辑。是否可以在 Scheme / Racket 中定义?
这感觉像是一个 XY 问题,所以我不知道这是否对您有帮助,但是:
正如@Renzo 评论的那样,如果您不需要在 运行 时执行此操作,那么在编译时使用宏来执行此操作可能会更干净、更快。
我不明白为什么您需要一个 get-function-variadic
的 returns 函数...不是可变的。但是我想你可以使用 procedure-reduce-arity
在你的例子中得到预期的结果:
#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)))
这是一个通过宏的解决方案。我设计它时仍然不知道 (procedure-reduce-arity) 函数(比这个解决方案更通用)。
(define-syntax-rule (variadic->fixed-arity f arguments ...)
(lambda (arguments ...) (f arguments ...)))
(define-for-syntax tails (lambda (l) (if (null? l) (list l) (cons l (tails (cdr l))))))
(define-for-syntax n 10)
(define-syntax (variadic->fixed-arities-up-to-n stx)
(syntax-case stx ()
[(variadic->fixed-arities-up-to-n f)
(let* ([arguments (generate-temporaries (build-list n values))]
[arguments-sets (reverse (tails arguments))])
#`(list
#,@(map (lambda (arguments-set)
#`(variadic->fixed-arity f #,@arguments-set))
arguments-sets)))]))
(define (get-function-of-arity f n)
(define functions-of-fixed-arities (variadic->fixed-arities-up-to-n f))
(if (n . >= . (length functions-of-fixed-arities))
(error "increase number of generated fixed-arities functions")
(list-ref functions-of-fixed-arities n)))
(procedure-arity (get-function-of-arity + 7)) ; returns 7
(apply (get-function-of-arity + 7) (make-list 7 3)) ; returns 21