From 589f598e079097a4c16859d370031e16e711a7a2 Mon Sep 17 00:00:00 2001 From: Ivan Yonchovski Date: Sun, 17 May 2020 23:08:32 +0300 Subject: [PATCH] Introduce -defun - I used `-lambda` as a base, tried several versions with extracting the common code but neither of them made the code more readable(IMO). - Removed the restrictions against doing `(-lambda () ...)` which does not seem to needed. --- dash.el | 48 +++++++++++++++++++++++++++++++++++++++++------- dev/examples.el | 13 +++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/dash.el b/dash.el index 1fc2ec83..5631aa91 100644 --- a/dash.el +++ b/dash.el @@ -2146,27 +2146,61 @@ such that: (-lambda (x y ...) body) has the usual semantics of `lambda'. Furthermore, these get -translated into normal lambda, so there is no performance +translated into a normal `lambda', so there is no performance penalty. -See `-let' for the description of destructuring mechanism." +See `-let' for a description of the destructuring mechanism." (declare (doc-string 2) (indent defun) (debug (&define sexp [&optional stringp] [&optional ("interactive" interactive)] def-body))) (cond - ((not (consp match-form)) - (signal 'wrong-type-argument "match-form must be a list")) + ((nlistp match-form) + (signal 'wrong-type-argument (list #'listp match-form))) ;; no destructuring, so just return regular lambda to make things faster - ((-all? 'symbolp match-form) + ((-all? #'symbolp match-form) `(lambda ,match-form ,@body)) (t - (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) + (let ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) ;; TODO: because inputs to the lambda are evaluated only once, ;; -let* need not to create the extra bindings to ensure that. ;; We should find a way to optimize that. Not critical however. - `(lambda ,(--map (cadr it) inputs) + `(lambda ,(-map #'cadr inputs) + (-let* ,inputs ,@body)))))) + +(defmacro -defun (name match-form &rest body) + "Define NAME as a function which destructures its input as MATCH-FORM and executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-defun (x) body) + (-defun (x y ...) body) + +has the usual semantics of `defun'. Furthermore, these get +translated into a normal `defun', so there is no performance +penalty. + +See `-let' for a description of the destructuring mechanism." + (declare (doc-string 3) (indent defun) + (debug (&define name sexp + [&optional stringp] + [&optional ("declare" &rest sexp)] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((nlistp match-form) + (signal 'wrong-type-argument (list #'listp match-form))) + ;; no destructuring, so just return regular defun to make things faster + ((-all? #'symbolp match-form) + `(defun ,name ,match-form ,@body)) + (t + (let ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form))) + ;; TODO: because inputs to the defun are evaluated only once, + ;; -let* need not to create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(defun ,name ,(-map #'cadr inputs) (-let* ,inputs ,@body)))))) (defmacro -setq (&rest forms) diff --git a/dev/examples.el b/dev/examples.el index 5c37b3ea..e0807f64 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -1259,6 +1259,19 @@ new list." (funcall (-lambda (a b) (+ a b)) 1 2) => 3 (funcall (-lambda (a (b c)) (+ a b c)) 1 (list 2 3)) => 6) + (defexamples -defun + (progn + (-defun dash-plus ((x y)) + (+ x y)) + + (dash-plus '(1 2))) => 3 + + (progn + (-defun a+b ((&plist :a a :b b)) + (+ a b)) + + (a+b '(:a 1 :b 2))) => 3) + (defexamples -setq (progn (-setq a 1) a) => 1 (progn (-setq (a b) (list 1 2)) (list a b)) => '(1 2)