【问题标题】:How to recreate apply in scheme如何在方案中重新创建应用
【发布时间】:2017-04-13 16:24:00
【问题描述】:
我将如何创建在方案中应用的函数?
一个与它做同样事情的 my-apply 函数。
(define (my-apply fn lst)
(if (null? lst)
我不知道从这里去哪里或如何开始。
【问题讨论】:
标签:
function
recursion
scheme
lisp
apply
【解决方案1】:
我认为apply比eval“更基础”,所以下面是作弊:
(define (my-apply func args)
(eval `(,func ,@args)))
如果没有eval,我认为你做不到。
【解决方案2】:
不久前我创建了一个 lisp 解释器,它有 eval 和宏,但它没有 apply。我想知道是否有办法让我的口译员支持apply,所以努力尝试一下。这是我的第一次尝试:
(define (my-apply proc args)
(eval (cons proc args)))
这显然不起作用,因为函数和参数列表被计算了两次。例如。 (my-apply cons '(a b)) 会给你(cons a b) 而不是(cons 'a 'b)。然后我认为这可能是宏的工作,但由于参数列表在宏扩展时未知,因此放弃了这个想法。程序必须如此,尽管我可以在将列表传递给eval之前引用该列表。
(define (my-apply proc args)
(define (q v)
(list 'quote v))
(eval (cons proc (map q args))))
这确实有效,但这比本地 apply 撤消工作 eval 所做的工作要多得多。
如果你不被允许使用eval,那你就真的不走运了。这是不可能的。在不使用apply 的情况下实现eval 也是如此,从那时起你就无法使用原语。
【解决方案3】:
(define (my-two-arg-apply f a)
(let ((l (length a)))
(cond ((= l 0) (f))
((= l 1) (f (car a)))
((= l 2) (f (car a) (cadr a))
...
((= l 5) (f (car a) (cadr a) ... (caddddr a)))
...
((= l 7) (f (car a) (cadr a) ... (caddddr a)
(list-ref a 5) (list-ref a 6)))
... ;; lots more cases
(else (error "argument passing limit exceeded")))))
宏可用于生成所需的大量代码。
error 在 R6RS 中被引入。令人惊讶的是,在此之前,Scheme 程序没有合理的方法来报告错误。
甚至不要考虑制作pop 宏并使用(f (pop a) (pop a) ... (pop a)) 模式;与 ANSI CL 等其他 Lisp 方言不同,Scheme 没有定义函数参数的评估顺序。