---
layout: ../Site.layout.js
---
# `cl-series`, vector multiplication, `assert` and lisp interactivity norms
- «.emacs eev setup»  (to "emacs eev setup")
- «.example draft code»       (to "example draft code")
- «.vector multiplier macro»  (to "vector multiplier macro")
- «.using that in the repl»   (to "using that in the repl")
- - «.generate length 2»      (to "generate length 2")
- - «.correct dimensions»     (to "correct dimensions")
- - «.incorrect dimensions»   (to "incorrect dimensions")
- - «.interactive resolution menu»    (to "interactive resolution menu")
- - «.Generated value-fixing prompts» (to "Generated value-fixing prompts")
- «.sans assertion»   (to "sans assertion")
- - «.jagged everything-right»        (to "jagged everything-right")
- - «.jagged dimension mismatch... cotruncation?»     (to "jagged dimension mismatch... cotruncation?")
- «.summary»  (to "summary")
- «.fin»      (to "fin")

I thought I should furnish [our incredible discussion yesterday about common lisp macro *assertables* with Vassil Nikolov and Kent M. Pitman](/show/Vassil-Nikolov-Kent-Pitman-assertables-compilation-declare) with my own practical example of [`assert` similar to the hyperspec's example](https://www.lispworks.com/documentation/HyperSpec/Body/m_assert.htm).

Vassil is working (when he has time) on an his *assertables* `macro`s for hierarchical, programmatic control of including and excluding assertions in code.

I will write a trivial vector multiplication using [`cl-series`](https://gitlab.common-lisp.net/rtoy/cl-series/\-/wikis/Series-User's-Guide) - i.e., a lazy, tight, declarative, generated in-order traversal, withstanding that this is a highschoolish task.

We will write a macro that generates a specific dimension vector multiplier, and `assert` that arguements' dimensions are correct. The assertion will turn out to be important.

While writing this, it also occured to me that the interactive expert useage generated by lisp for me in order to help me in the context of my failed assertion is very important iconic classic lisp useage.

# emacs eev and setup
- «emacs eev setup»  (to ".emacs eev setup")

```
#|
 (eepitch-sbcl)
 (eepitch-kill)
 (eepitch-sbcl)
(require :series)
(series::install)
|#
```

# Example of planned vector multiplication
- «example draft code»  (to ".example draft code")

```
(equal ((generate-vector-multiplier (2))
       '(1 2) '((3)
                (4)))
      (+ (* 1 3)
         (* 2 4)))
```

# Common lisp macro to generate a vector multiplier lambda
- «vector multiplier macro»  (to ".vector multiplier macro")

```
(defmacro generate-vector-multiplier ((lengths))
 `(lambda (a b)
    (assert (and (equal (length a) ,lengths)
                 (equal (length b) ,lengths))
            (a b)
            "Dimension 1 of the first vector, ~d,
should be equal to dimension 2 of the second vector, ~d,
should be equal to the vector-multiplier's length, ~d."
            (length a) (length b) ,lengths)

    (let* ((series-a (scan a))
           (series-b (scan b))
           (series-bᵀ (#Mcar series-b))
           (series-abᵀ (#M* series-a series-bᵀ)))
      (collect-sum series-abᵀ))))
```

# Example use in the repl
- «using that in the repl»  (to ".using that in the repl")

## `generate-vector-multiplier` for lengths `2`.
- - «generate length 2»  (to ".generate length 2")

```
CL-USER> (generate-vector-multiplier (2))
#<FUNCTION (LAMBDA (A B)) {5373E07B}>
```

## Try with correct vector dimensions
- - «correct dimensions»  (to ".correct dimensions")

```
CL-USER> (funcall * '(1 2) '((3) (4)))
11
```

Great. Also remember [in lisp interaction](https://www.lispworks.com/documentation/HyperSpec/Body/v__stst_.htm), `*` is 'the last first return', `**` is 'the second last first return', `***`, third.

## Try with an incorrect vector dimension
- - «incorrect dimensions»  (to ".incorrect dimensions")

Looks good but what about `(funcall ** '(1 2) '((3) (4) (5)))`? We end up interactively in lisp's debugger with the message we just wrote:

## The assertion fails message/debugger menu
- - «interactive resolution menu»  (to ".interactive resolution menu")

```
Dimension 1 of the first vector, 2,
should be equal to dimension 2 of the second vector, 3,
should be equal to the vector-multiplier's length, 2.
  [Condition of type SIMPLE-ERROR]

Restarts:
0: [CONTINUE] Retry assertion with new values for A, B.
1: [RETRY] Retry SLIME REPL evaluation request.
2: [*ABORT] Return to SLIME's top level.
3: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1001380003}>)

Backtrace:
 0: (SB-KERNEL:ASSERT-ERROR (AND (EQUAL (LENGTH A) 2) (EQUAL (LENGTH B) 2)) (A B) "Dimension 1 of the first vector, ~d, ..)
 1: ((LAMBDA (A B)) (1 2) ((3) (4) (5)))
 2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FUNCALL ** (QUOTE (1 2)) (QUOTE (# # #))) #<NULL-LEXENV>)
 3: (EVAL (FUNCALL ** (QUOTE (1 2)) (QUOTE (# # #))))
--more--
```
I clicked `CONTINUE`:

## Continuing (prompts me for values to change)
- - «Generated value-fixing prompts»  (to ".Generated value-fixing prompts")

```
CL-USER> (funcall ** '(1 2) '((3) (4) (5)))
The old value of A is (1 2).
Do you want to supply a new value?  (y or n) n
The old value of B is ((3) (4) (5)).
Do you want to supply a new value?  (y or n) y
Type a form to be evaluated:
#((3) (4))
11
```

You can also notice that I snuck in a vector (of lists) instead of a list; `cl-series` operates on lisp *sequences*, not particularly just vectors or lists.

# Alternate, assertionless lambda problem
- «sans assertion»  (to ".sans assertion")

We find out that our assertion was critically important, because of a *desireable* property of `cl-series`. Let's make a version without the assertion of matching lengths:

```
(defmacro generate-jagged-vector-multiplier ((lengths))
 `(lambda (a b)

    (let* ((series-a (scan a))
           (series-b (scan b))
           (series-bᵀ (#Mcar series-b))
           (series-abᵀ (#M* series-a series-bᵀ)))
      (collect-sum series-abᵀ))))
```

## Try it for the everything-right case above:
- - «jagged everything-right»  (to ".jagged everything-right")

```
CL-USER> (generate-jagged-vector-multiplier (2))
; caught STYLE-WARNING:
;   The variable LENGTHS is defined but never used.
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
GENERATE-JAGGED-VECTOR-MULTIPLIER
CL-USER> (generate-jagged-vector-multiplier (2))
#<FUNCTION (LAMBDA (A B)) {5373E7DB}>
CL-USER> (funcall * '(1 2) '((3) (4)))
11
```

Well, the warning kind of gives it away.

## Try it for the vector mismatch case above:
- - «jagged dimension mismatch... cotruncation?»  (to ".jagged dimension mismatch... cotruncation?")

```
CL-USER> (funcall ** '(1 2) '((3) (4) (5)))
11
```

`cl-series` lazily truncated the second vector without asking us. This is because series handles infinities for example through this laziness, cotruncating computation to the shortest participant (basically to implicitly cut out infinities).

However our intent here was vector multiplication, which is not defined on mismatched vector lengths. Furthermore, as we were warned above, our `lengths` arguement above is now actually doing nothing:

```
CL-USER> (funcall *** '(1 2 3) '((3) (4) (5)))
26
```

# In summary
- «summary»  (to ".summary")

We included an assertion when generating specific-length matrix multiplication lambdas [per the hyperspec](https://www.lispworks.com/documentation/HyperSpec/Body/m_assert.htm)

```
(defmacro generate-vector-multiplier ((lengths))
 `(lambda (a b)
    (assert (and (equal (length a) ,lengths)
                 (equal (length b) ,lengths))
            (a b)
            "Dimension 1 of the first vector, ~d,
should be equal to dimension 2 of the second vector, ~d,
should be equal to the vector-multiplier's length, ~d."
            (length a) (length b) ,lengths)

    (let* ((series-a (scan a))
           (series-b (scan b))
           (series-bᵀ (#Mcar series-b))
           (series-abᵀ (#M* series-a series-bᵀ)))
      (collect-sum series-abᵀ))))
```

this generated a choice for me to interactively resolve some assertion-failing data (note that I didn't write these prompts):

```
CL-USER> (funcall ** '(1 2) '((3) (4) (5)))

<I select CONTINUE (with new values) from the interactive condition handler>

The old value of A is (1 2).
Do you want to supply a new value?  (y or n) n
The old value of B is ((3) (4) (5)).
Do you want to supply a new value?  (y or n) y
Type a form to be evaluated:
#((3) (4))
11
```

without the assertion, `cl-series` was implicitly cotruncating the incorrect length vector - good for working with infinities, bad for our definition of vector multiplication.

# Fin
- «fin»  (to ".fin")

What do you think about ANSI CL's assertions, my example, and `cl-series`' historic, modern, declarative, lazy evaluation? Also, thinking about it, I think the way common lisp is seen to actively engage with its expert lispuser about the failed assertion *with the image still in the context that the assertion failed* is an incredibly important useage.

Anyway, talk [in the Mastodon thread please](https://gamerplus.org/@screwlisp/114667715347406418) (or come on the lispy gopher show live with everyone).

I hope we can share and discuss these *futuristic* and *bleeding edge* ANSI common lisp features and concerns with everyone who kinda feels these ideas should have existed (and actually do) and even have been standardized with ANSI, and be actively pursued and expanded with `substandards` like `cl-series` and `assertables`.

Please do share and disseminate this article and yesterday's interview and everything by whatever your personal channels are if you agree.