是否可以实现自动curry到Lisp系列语言?

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)

  • 总的来说很棒的答案,但你提供的小snipplet证明是非常有用的,所以我不能接受另一个答案,但这. (2认同)