我试图通过尝试不同的语言实现来理解LIsp。
我目前正在尝试创建一个函数,它接受一个lambda函数列表,并从右到左,从左到右组合它们。
这是一个我不清楚的例子
(apply-right-left '((lambda (x) (+ x 1)) (lambda (x) (* x 2))) 1)
--> 3
感谢...
答案 0 :(得分:4)
请参阅PORT/ext.lisp中的compose
:
(defun compose (&rest functions)
"Return the composition of all the arguments.
All FUNCTIONS should take one argument, except for
the last one, which can take several."
(reduce (lambda (f0 f1)
(lambda (&rest args) (funcall f0 (apply f1 args))))
functions :initial-value #'identity))
因此,
(funcall (compose (lambda (x) (+ x 1)) (lambda (x) (* x 2))) 1)
==> 3
如果您想从左到右撰写,则需要将:from-end
传递给reduce
。
如果您不想使用上述compose
创建中间函数,可以直接使用reduce
:
(reduce #'funcall
(list (lambda (x) (+ x 1)) (lambda (x) (* x 2)))
:initial-value 1
:from-end t)
==> 3
答案 1 :(得分:1)
这里的功能(需要SRFI 26):
(define (wrap x)
(cut values x <...>))
(define (call-compose . args)
(cond ((null? args) (values))
((procedure? (car args))
(call-with-values (cut apply call-compose (cdr args)) (car args)))
(else
(apply call-compose (wrap (car args)) (cdr args)))))
果然,如果你使用测试功能调用它,你会得到:
> (call-compose (lambda (x) (+ x 1)) (lambda (x) (* x 2)) 1)
3
你甚至可以做类似的事情(除了+
和*
的参数被交换之外,就像你上面的例子一样):
> (call-compose + 1 * 2 1)
3
(这与(+ 1 (* 2 1))
相同。)
这篇文章的其余部分不再深入了解。如果您是Scheme的新手,可能没有意义。 : - )
魔术的关键部分是函数包装器wrap
。它接受任何值并返回一个带有任意数量参数的函数,并返回添加了这些参数的值(作为多个值)。例如:
> (define wrap1 (wrap 1))
> (wrap1 2 3 4)
1
2
3
4
因此,使用(call-compose + 1 * 2 1)
之类的表达式,与(call-compose + (wrap 1) * (wrap 2) (wrap 1))
相同,后者转换为(mv + (mv (wrap 1) (mv * (mv (wrap 2) (mv (wrap 1))))))
(其中mv
为a macro that provides the same functionality as Common Lisp's multiple-value-call
)。
您也可以将wrap
与函数对象一起使用。这允许您将函数对象传递给高阶函数。如,
> (call-compose map (wrap +) '(1 2 3) '(4 5 6))
(5 7 9)
为了获得更多乐趣,我还将compose
扩展为具有相同的行为:
(define (compose . args)
(cond ((null? args) values)
((procedure? (car args))
(lambda xs
(call-with-values (cut apply (apply compose (cdr args)) xs) (car args))))
(else
(apply compose (wrap (car args)) (cdr args)))))