2013-04-17 3 views
3

Я изучаю макросистему на Схеме, и я думал, что реализация карри-функций станет хорошим началом. Это то, что я приготовил:Функции 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 (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 
+2

Это ** не ** создание _curried_ функций; он создает _partially прикладные_ функции. С помощью '(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

Вы не говорите, какую версию Схемы вы используете. Похоже, что он не поддерживает шаблоны «точка» в макросах.

В Ракетка, это выглядит, как работает ваш код:

#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 

.

BTW, я думаю, что я написал бы это как два макроса; двойное назначение названия «функция» немного отрывочно ... :)

+0

Я использую Chicken Scheme версию '4.7. 0'. –

+2

звучит, как схема курицы, не поддерживает этот шаблон, как написано. Возможно, вы хотите попробовать Racket? ... :) –