2013-04-17 72 views
3

我正在學習Scheme中的宏系統,我認爲實現curried函數將是一個好的開始。這是我製作的:使用宏的Scheme中的Currying函數

(define-syntax function 
    (syntax-rules() 
     ((_() body ...) (lambda() body ...)) 
     ((_ (param) body ...) (lambda (param) body ...)) 
     ((_ (param_1 param_2 params ...) body ...) (lambda (param_1 . rest) 
      (let ((k (function (param_2 params ...) body ...))) 
       (if (null? rest) k (apply k rest))))) 
     ((_ name params body ...) (define name (function params body ...))))) 

此代碼按預期工作。舉例如下我可以定義一個add功能:

(function add (x y) (+ x y)) 

然後我可以正常調用它:

(add 2 3) ; => 5 

此外,我可以很容易地部分地應用它:

(map (add 10) '(2 3 5 7)) ; => (12 13 15 17) 

現在我正在考慮允許具有其他參數的函數被粘貼。所以我增加了一個新的語法規則:

((_ (param . params) body ...) (lambda (param . params) body ...)) 

不幸的是,當我嘗試使用這個法則它給了我一個錯誤創建一個函數:

(function add (x . y) (apply + `(,x ,@y))) 

這是錯誤消息:

Error: invalid syntax in macro form: (x . y) 

    Call history: 

    <eval> (##sys#= len7 0) 
    <eval> (loop11 (##sys#cdr l6) (##sys#+ len7 -1)) 
    <eval> (##sys#cdr l6) 
    <eval> (##sys#+ len7 -1) 
    <eval> (##sys#= len7 0) 
    <eval> (loop11 (##sys#cdr l6) (##sys#+ len7 -1)) 
    <eval> (##sys#cdr l6) 
    <eval> (##sys#+ len7 -1) 
    <eval> (##sys#= len7 0) 
    <eval> (##sys#eq? l6 (quote())) 
    <eval> (##sys#car tail15) 
    <eval> (##sys#cdr tail15) 
    <eval> (##sys#cons (rename14 (##core#syntax lambda)) (##sys#cons param body)) 
    <eval> (rename14 (##core#syntax lambda)) 
    <eval> (##sys#cons param body) 
    <syntax>  (##core#lambda add (x . y) (apply + (quasiquote ((unquote x) (unquote-splicing y))))) <- 

我做錯了什麼?

回答

3

[評論是正確的;這個答案不是咖喱,它是部分評價。]

只是你知道,你不需要使用define-syntax來支持咖喱。通常在不需要時使用語法會被忽視,因爲1)語法引入了不同的評估規則,2)語法不能用作值。

這裏有兩種實現方式,一個是(左)咖喱一個右咖喱:

> (define add-5 (curry + 5)) 
> (add-5 5) 
10 
+2

這是**不**創建_curried_函數;它正在創建_partially applied_函數。用'(define(fxyz)(+ x(* yz)))(define g(curry f 1))','((g 2)3)'應該返回7.但是你必須調用'((curry g 2)3)。而在OP代碼之後,'(函數g(xyz)(+ x(* yz)))','(g 1 2 3)'=='((g 1 2)3)'=='(( (g 1)2)3)'== 7。 –

2

你不說你正在使用什麼版本的Scheme。它似乎不支持宏中的「點」模式。

球拍,它看起來像你的代碼的工作:

#lang racket 

(define-syntax function 
    (syntax-rules() 
     ((_() body ...) (lambda() body ...)) 
     ((_ (param) body ...) (lambda (param) body ...)) 
     ((_ (param_1 param_2 params ...) body ...) (lambda (param_1 . rest) 
                (let ((k (function (param_2 params ...) body ...))) 
                (if (null? rest) k (apply k rest))))) 

     ((_ (param . params) body ...) (lambda (param . params) body ...)) 
     ((_ name params body ...) (define name (function params body ...))))) 

(function add (x . y) (apply + `(,x ,@y))) 

(add 2 3) 

運行這將產生答案

5 

順便說一句,我想我會寫這兩個宏;名稱'功能'的雙重目的有點簡單... :)

+0

我用雞方案版本'4.7:

(define (curry func . curry-args) (lambda args (apply func (append curry-args args)))) (define (rcurry func . curry-args) (lambda args (apply func (append args curry-args)))) 

以此作爲例子。 0'。 –

+2

聽起來像雞計劃不支持這種模式寫作。也許你想嘗試一下Racket? ... :) –