Is it possible to implement auto-currying to the Lisp-family languages?

前端 未结 6 2037
夕颜
夕颜 2020-12-31 06:15

That is, when you call a function with >1 arity with only one argument, it should, instead of displaying an error, curry that argument and return the resulting function with

6条回答
  •  甜味超标
    2020-12-31 06:57

    As noted by Alex W, the Common Lisp Cookbook does give an example of a "curry" function for Common Lisp. The specific example is further down on that page:

    (declaim (ftype (function (function &rest t) function) curry)
             (inline curry)) ;; optional
    (defun curry (function &rest args)
      (lambda (&rest more-args)
        (apply function (append args more-args))))
    

    Auto-currying shouldn't be that hard to implement, so I took a crack at it. Note that the following isn't extensively tested, and doesn't check that there aren't too many args (the function just completes when there are that number or more):

    (defun auto-curry (function num-args)
      (lambda (&rest args)
        (if (>= (length args) num-args)
            (apply function args)
            (auto-curry (apply (curry #'curry function) args)
                        (- num-args (length args))))))
    

    Seems to work, though:

    * (auto-curry #'+ 3)
    #
    
    * (funcall (auto-curry #'+ 3) 1)
    #
    
    * (funcall (funcall (funcall (auto-curry #'+ 3) 1) 2) 5)
    8
    
    * (funcall (funcall (auto-curry #'+ 3) 3 4) 7)
    14
    

    A primitive (doesn't handle full lambda lists properly, just simple parameter lists) version of some macro syntax sugar over the above:

    (defmacro defun-auto-curry (fn-name (&rest args) &body body)
      (let ((currying-args (gensym)))
        `(defun ,fn-name (&rest ,currying-args)
           (apply (auto-curry (lambda (,@args) ,@body)
                              ,(length args))
                  ,currying-args))))
    

    Seems to work, though the need for funcall is still annoying:

    * (defun-auto-curry auto-curry-+ (x y z)
        (+ x y z))
    AUTO-CURRY-+
    
    * (funcall (auto-curry-+ 1) 2 3)
    6
    
    * (auto-curry-+ 1)
    #
    

提交回复
热议问题