letv

2024-10-12

The LETV Package. Exports two macros, LETV and LETV* that allow to combine standard LET and LET* constucts with MULTIPLE-VALUE-BIND in a possible less verbose way that also requires less indentation.

Upstream URL

gitlab.common-lisp.net/mantoniotti/letv

Author

Marco Antoniotti

License

BSD
README

The LETV and LETV* Macros

Marco Antoniotti <mantoniotti [at] common-lisp.net>
2023-03-09

See the file COPYING for copyright and licensing information.

This little hack introduces two handy Common Lisp macros, LETV and LETV* that allow you to mix regular LET and MULTIPLE-VALUE-BIND forms in a less verbose way. The amount of indentation needed is also reduced.

The syntax of LETV (or LETV*) is very "loopy", with a nod to SML/OCaml/F#/Haskell/Julia. The current syntax is the following:

letv     ::= 'LETV' [vars] [IN [body]]
letvstar ::= 'LETV*' [vars] [IN [body]]

vars     ::= var | var vars

var      ::= ids '=' <form> [decls]

decls    ::= decl | decl decls
decl     ::= OF-TYPE idtypes

ids      ::= <symbol> | '(' <symbol> + ')'
idtypes	 ::= <type designator> | '(' <type designator> + ')'

body     ::= [<declarations>] <form> *

(I know: the grammar is not completely kosher, but I trust you will understand it.)

The two macros expand in forms that mimic the semantics of LET, LET* and MULTIPLE-VALUE-BIND. All type declarations, if present, are properly handled via LOCALLY forms.

LETV expands into a LET, with variable initialized by PSETQs and MULTIPLE-VALUE-SETQs.

LETV* expands into a form that is an interleaving of LET* and MULTIPLE-VALUE-BIND.

Examples

  1. Simple case:
    (letv x = 42 in (format t "The answer is ~D.~%" x))
  2. Same with declaraion:
    (letv x = 42 of-type fixnum
          in (format t "The answer is ~D." x))
  3. Simple case with MULTIPLE-VALUE-BIND:
    (letv (v found) = (gethash 'the-key *my-hash-table*)
          in (if found
                 (format t "Found THE-KEY, doing stuff.~%")
                 (error "THE-KEY not found.")))
  4. Mixing things up:
    (letv (v found) = (gethash 'the-key *my-hash-table*)
                    of-type (fixnum boolean)
          x = 42
          in (if found
                 (format t "Found THE-KEY, adding to the answer ~D.~%"
                         (+ v x))
                 (error "THE-KEY not found.")))
  5. With LETV*:
    (letv* (v found) = (gethash 'the-key *my-hash-table*)
                     of-type (fixnum boolean)
           x = (when found (+ v 42))
           in (if found
                  (format t "Found THE-KEY, adding to the answer ~D.~%"
                          x)
                  (error "THE-KEY not found.")))
  6. The other way around.
    (letv x = 42 of-type integer
          (v found) = (gethash 'the-key *my-hash-table*)
                    of-type (fixnum boolean)
          in (if found
                 (format t "Found THE-KEY, adding to the answer ~D.~%"
                         (+ v x))
                 (error "THE-KEY not found.")))
  7. A more compelling example.
    (letv* (p found) = (gethash 'the-key *points-table*) of-type (point)
           (x y) = (if found
                       (unpack-point p)
                       (values :missing :missing))
           in
           ;; Adding declarations here also works.
    
           (declare (type point p)
                    (type  (or real (eql :missing)) x y))
    
           (do-stuff-with x y)
           (do-things-with p))

All the examples are meant to illustrate the use of LETV and LETV*.

Notes

LETV and LETV* are obviously not the first macros of this kind floating around: others are available and all have their niceties. But I never claimed not to suffer form NIH syndrome.

LETV and LETV* do not do "destructuring" or "pattern matching". That is a different can of worms; but you can check cl-unification for a library (always by yours truly) that provides facilities in that sense.

A NOTE ON FORKING

Of course you are free to fork the project subject to the current licensing scheme. However, before you do so, I ask you to consider plain old "cooperation" by asking me to become a developer. It helps keeping the entropy level at an acceptable level.

Dependencies (0)

    Dependents (0)

      • GitHub
      • Quicklisp