4

我正在学习 Scheme 中的宏系统,我认为实现 curried 函数将是一个好的开始。这是我做的:

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

我究竟做错了什么?

4

2 回答 2

2

你没有说你使用的是什么版本的方案。它似乎不支持宏中的“点”模式。

在 Racket 中,您的代码似乎可以正常工作:

#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

.

顺便说一句,我想我会把它写成两个宏;'function'这个名字的双重用途有点粗略...... :)

于 2013-04-17T17:58:26.493 回答
2

[评论正确;这个答案不是currying,而是部分评估。]

只是让你知道,你不需要使用define-syntax来支持柯里化。通常在不需要时使用语法是不受欢迎的,因为 1) 语法引入了不同的评估规则,2) 语法不能用作值。

这里有两种实现,一种用于(左)咖喱,一种用于右咖喱:

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

以此为例:

> (define add-5 (curry + 5))
> (add-5 5)
10
于 2013-04-18T02:53:58.983 回答