Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lisp chaining functions macro

Is there a ready made lisp macro that allows chaining (piping) of functions? I couldn't find one. I'll try to explain what I mean with this example.

Instead of using let* with lots of unused intermediate variables like this:

(let*
  ((var1 (f1 x y))
   (var2 (f2 x var1))
   (var3 (f1 var2 z)))
 var3)

I would like to have it written like this:

(->
  (f1 x y)
  (f2 x _)
  (f1 _ z))

where, obviously _ will be return value from previous expression. A plus is if would be possible to use _1, _2, ... to reference previously returned values.

This is the idea, exact syntax is not that important.

I know this is not that hard to write, but seems so useful that it has to be written already.

like image 372
Marko Avatar asked Dec 08 '22 04:12

Marko


2 Answers

Something like this?

(defun chain-expander (forms)
  (cond ((null (cdr forms)) (car forms))
    (t `(let ((it ,(car forms)))
          ,(chain-expander (cdr forms))))))

(defun chain-counted-expander (forms counter)
  (cond ((null (cdr forms)) (car forms))
    (t (let* ((name (format nil "_~d" counter))
          (anaphora (or (find-symbol name) (intern name))))
         `(let ((,anaphora ,(car forms)))
        ,(chain-counted-expander (cdr forms) (1+ counter)))))))

(defmacro chain (&body forms)
  (chain-expander forms))

If you'd prefer something where _1, _2, and so on is usable, simply replace the call to CHAIN-EXPANDER with a call to CHAIN-COUNTED-EXPANDER (with your preferred first number, I'd suggest either 0 or 1). Note that it explicitly only caters to using _N as a reference, but changing it so that it also binds _ for each subsequent level is not very hard.

like image 99
Vatine Avatar answered Dec 25 '22 06:12

Vatine


Why not just

(f1 (f2 x (f1 x y)) z)

?

Or make that into a function ?

like image 39
Christoffer Hammarström Avatar answered Dec 25 '22 04:12

Christoffer Hammarström