2015-09-08 103 views
1

如何在Scheme /球拍中定義返回特定區域功能的功能?功能在特定區域的方案/球拍返回功能

目前,我有我的代碼如下:

(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 
    )) 

它返回一個函數的元數當然是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)))))) 

但隨後返回可變參數功能:

(procedure-arity (get-function-variadic 3)) ; returns #(struct:arity-at-least 0) 

,使所有這些工作只是作爲正常計劃的可變參數 「+」 的:

((get-function-variadic 3) 1 2 3) 

((get-function-variadic 3) 1 2) 
((get-function-variadic 3) 1 2 3 4) 

其實我只需要第一個返回結果,而其他人應該返回「錯誤數量的參數」錯誤。另外,在程序的其他部分,我依賴所生成函數的組合。所以,一個可變參數函數不適合我(即使它檢查「參數」的長度)。我需要由(get-function n)返回的一組不同整數區域的函數。是否可以在Scheme/Racket中定義?

+3

這是[宏](http://docs.racket-lang.org/guide/macros.html)的典型任務,而不是函數。 – Renzo

+0

@Renzo,我試了一下宏,請看下面。似乎工作。但是,Greg建議有更好的選擇。 – formalizm

回答

3

這感覺就像一個XY問題,所以我不知道這口井幫你,但:

由於@Renzo評論,如果你並不需要在運行時要做到這一點,它可能是更清潔而且在編譯時使用一個宏可以更快地完成它。

我不明白你爲什麼需要一個get-function-variadic返回函數是...不可變。不過,我想你可以使用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))) 
+1

謝謝,@Greg,這正是我所需要的。不知何故,我錯過了這個程序,減少了文檔中的參數。至於命名方面,我把它稱爲「variadic」,因爲它是可變的,並且我不能使它變得無變化。 :) – formalizm

+0

我試了一下宏,看下面。似乎工作。但是,你的解決方案顯然更好。 – formalizm

0

這裏是通過宏的解決方案。我設計它時仍然不知道(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