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



Marco Antoniotti



The LETV and LETV* Macros

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

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.


  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.~%"
                  (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))
           ;; 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*.


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.


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