Mai*_*tor 15 lisp scheme clojure common-lisp currying
也就是说,当你只用一个参数调用> 1 arity的函数时,它应该,而不是显示错误,咖喱该参数并返回生成的函数,减少arity.这是否可以使用Lisp的宏?
Eli*_*lay 14
如果你想要一个有用的结果,这是可能的,但并不容易.
如果你想要一种总是做简单currying的语言,那么实现起来很容易.您只需将多个输入的每个应用程序转换为嵌套应用程序,并将多个参数的函数转换为相同的应用程序.使用Racket的语言设施,这是一个非常简单的练习.(在其他lisps中,你可以通过代码中某些宏来获得类似的效果.)
(顺便说一句,我在Racket上面有一种语言可以做到这一点.它可以获得自动语言的完整可爱性,但它并不是实用的.)
但是,它不太有用,因为它只适用于一个参数的函数.您可以通过一些黑客攻击使其变得有用,例如,将您的语言的其余部分视为外语,并提供表单来使用它.另一种方法是为您的语言提供有关周围lisp功能的arity信息.这些都需要更多的工作.
另一种选择是检查每个应用程序.换句话说,你转过来
(f x y z)
Run Code Online (Sandbox Code Playgroud)
检查arity的代码,f如果没有足够的参数,将创建一个闭包.这本身并不太难,但会导致巨大的开销价格.你可以尝试使用一些关于你在宏级别中使用的函数arities的信息的类似技巧来知道应该在哪里创建这样的闭包 - 但这很难以基本相同的方式进行.
但是,在你想做的事情的高层次上,存在一个更为严重的问题.事实是变量功能只是不能很好地与自动currying.例如,采用如下表达式:
(+ 1 2 3)
您如何判断是否应按原样调用,或者是否应将其翻译为((+ 1 2) 3)?看来这里有一个简单的答案,但是这个怎么样?(翻译成你最喜欢的lisp方言)
(define foo (lambda xs (lambda ys (list xs ys))))
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您可以(foo 1 2 3)通过多种方式拆分.还有一个问题是你如何处理以下事情:
(list +)
Run Code Online (Sandbox Code Playgroud)
在这里你有+一个表达式,但你可以决定这与在零输入上应用它相同+,但是你如何编写一个表达式来计算加法函数?(旁注:ML和Haskell通过没有固定功能来解决这个问题......)
其中一些问题可以通过决定每个"真正的"应用程序必须具有parens来解决,因此它+本身永远不会被应用.但是,这种语言失去了很多可爱性,你仍然有问题要解决......
Ósc*_*pez 11
在Scheme中,可以使用以下curry过程来调整函数:
(define (add x y)
(+ x y))
(add 1 2) ; non-curried procedure call
(curry add) ; curried procedure, expects two arguments
((curry add) 1) ; curried procedure, expects one argument
(((curry add) 1) 2) ; curried procedure call
Run Code Online (Sandbox Code Playgroud)
来自Racket的文档:
[curry]返回一个程序,它是proc的curried版本.首次应用生成的过程时,除非给出它可以接受的最大参数数,否则结果是接受其他参数的过程.
您可以轻松实现curry在定义新过程时自动使用的宏,如下所示:
(define-syntax define-curried
(syntax-rules ()
((_ (f . a) body ...)
(define f (curry (lambda a (begin body ...)))))))
Run Code Online (Sandbox Code Playgroud)
现在将讨论以下定义add:
(define-curried (add a b)
(+ a b))
add
> #<procedure:curried>
(add 1)
> #<procedure:curried>
((add 1) 2)
> 3
(add 1 2)
> 3
Run Code Online (Sandbox Code Playgroud)