読者です 読者をやめる 読者になる 読者になる

カリー化関数

common lisp read macro

ふと思い立って、カリー化を行う関数を書いてみた。

(defun curry (fn &rest args)
  (lambda (&rest rest-args)
    (apply fn (append args rest-args))))

;;;
> (curry #'cons :first)
-->#<CLOSURE (LAMBDA (&REST REST-ARGS)) {B3BC96D}>

> (funcall * :second)
--> (:FIRST . :SECOND)


カリー化関数は他の誰かも書いているだろうと思って調べて見たら、『The Common Lisp Cookbook - Functions』というページで、(宣言を除けば)全く同じ定義の関数を見つけて、少し面白かった。

追記: シンタックスシュガー

書きやすくするために、(極めて)簡単なリードマクロを定義してみる。

;; [fn arg1 arg2 ...] -> (funcall fn arg1 arg2 ...)
(defun |[-reader| (stream arg)
  (declare (ignore arg))
  `(funcall ,@(read-delimited-list #\] stream t)))

(set-macro-character #\[ #'|[-reader|)
(set-macro-character #\] (get-macro-character #\) nil))

;; {fn-name arg1 arg2 ..} -> (curry #'fn-name arg1 arg2 ...)
(defun |{-reader| (stream arg)
  (declare (ignore arg))
  (destructuring-bind (fn . args) (read-delimited-list #\} stream t)
    `(curry #',fn ,@args)))

(set-macro-character #\{ #'|{-reader|)
(set-macro-character #\} (get-macro-character #\) nil))

;;;;
;;;;
> [{cons :first} :second]
--> (:FIRST . :SECOND)

>  (mapcar {+ 10} '(1 2 3))
--> (11 12 13)

前よりそれっぽくなったような気がする。