trivial/icfp-2016/usage.scrbl
2016-03-16 08:22:17 -04:00

560 lines
21 KiB
Racket
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#lang scribble/sigplan
@(require "common.rkt" racket/string racket/sandbox)
@; TODO 'need to' etc
@; TODO clever examples
@; TODO definition pane for examples
@; +------------
@; | f \in \interp
@; |
@; | > (f x)
@; | y
@; +------------
@; TODO remove all refs to implementation?
@title[#:tag "sec:usage"]{What we can learn from Values}
We have defined useful elaborators for a variety of
common programming tasks ranging from type-safe string formatting to
constant-folding of arithmetic.
These elaborators are implemented in Typed Racket@~cite[TypedRacket], a macro-extensible
typed language that compiles into Racket@~cite[plt-tr1].
An important component of Typed Racket's design is that all macros in a program
are fully expanded before type-checking begins.
This protocol lets us implement our elaborators as macros that expand into
typed code.
Each elaborator is defined as a @emph{local} transformation on syntax.
Code produced by an elaboration may be associated with compile-time values
for other elaborators to access.
Using these values, we support variable bindings and propagate information upward through
nested elaborations.
@parag{Conventions}
@itemlist[
@item{
Interpretation and elaboration functions are defined over symbolic expressions
and values; specifically, over @emph{syntax objects}.
To distinguish terms and syntax objects,
we quote the latter and typeset it in green.
Hence @racket[(λ (x) x)] is the identity function
and @racket['(λ (x) x)] is a syntax object.
} @item{
Values are typeset in @exact|{\RktVal{green}}| because their syntax and
term representations are identical.
} @item{
Syntax objects carry lexical information, but our examples treat them as
flat symbols.
} @item{
We use an infix @tt{::} to write explicit type annotations and casts,
for instance @racket[(x :: Integer)].
Annotations and casts normally have two different syntaxes, respectively
@racket[(ann x Integer)] and @racket[(cast x Integer)].
}
]
@; =============================================================================
@section{Format Strings}
@; TODO add note about the ridiculous survey figure? Something like 4/5 doctors
@; TODO note regexp is the first?
Format strings are the world's second most-loved domain-specific language (DSL).
@; @~cite[wmpk-algol-1968]
All strings are valid format strings; additionally, a format string may contain
@emph{format directives} describing @emph{where} and @emph{how} values can be
spliced into the format string.
@; TODO scheme or common lisp?
Racket follows the Lisp tradition@~cite[s-lisp-1990] of using a tilde character (@tt{~})
to prefix format directives.
For example, @racket[~s] converts any value to a string and @racket[~b] converts a
number to binary form.
@exact|{
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{7}\RktPn{)}
\evalsto\RktOut{binary(7) = 111}
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
}|
If the format directives do not match the arguments to @racket[printf], most
languages fail at run-time.
This is a simple kind of value error that could be caught statically.
@exact|{
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\Scribtexttt{{\Stttextmore} }\RktPn{(}\RktSym{printf}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"binary($\sim$s) = $\sim$b"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"7"}\RktPn{)}
\evalsto\RktErr{printf: format string requires an exact{-}number}
\begin{SingleColumn}\end{SingleColumn}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
}|
Detecting inconsistencies between a format string and its arguments is straightforward
if we define an interpretation @racket[fmt->types] for
reading types from a format string value.
In Typed Racket this function is rather simple because the most common
directives accept @code{Any} type of value.
@exact|{
\hfill\fbox{\RktMeta{fmt->types} $\in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (fmt->types "binary(~s) = ~b")
==> '[Any Integer]
> (fmt->types '(λ (x) x))
==> #false
]
Now to use @racket[fmt->types] in an elaboration.
Given a call to @racket[printf], we check the number of arguments and
add type annotations using the inferred types.
For all other syntax patterns, @racket[t-printf] is the identity elaboration.
@exact|{
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> '(printf "~a")
==>
> '(printf "~b" 2)
==> '(printf "~b" (2 :: Integer))
> 'printf
==> 'printf
]
The first example is rejected immediately as a syntax error.
The second is a valid elaboration, but will lead to a static type error.
Put another way, the format string @racket{~b} specializes the type of
@racket[printf] from @racket[(String Any * -> Void)] to @racket[(String Integer -> Void)].
The third example demonstrates that higher-order
uses of @racket[printf] default to the standard, unspecialized behavior.
@; =============================================================================
@section{Regular Expressions}
Regular expressions are often used to capture sub-patterns within a string.
@racketblock[
> (regexp-match #rx"-(2*)-" "111-222-3333")
==> '("-222-" "222")
> (regexp-match #rx"¥(.*)" "$2,000")
==> #false
]
The first argument to @racket[regexp-match] is a regular expression pattern.
Inside the pattern, the parentheses delimit sub-pattern @emph{groups}, the dots match
any single character, and the Kleene star matches zero-or-more repetitions
of the pattern-or-character preceding it.
The second argument is a string to match against the pattern.
If the match succeeds, the result is a list containing the entire matched string
and substrings corresponding to each group captured by a sub-pattern.
If the match fails, @racket[regexp-match] returns @racket[#false].
Groups may fail to capture even when the overall match succeeds.
This can happen when a group is followed by a Kleene star.
@racketblock[
> (regexp-match #rx"(a)*(b)" "b")
==> '("b" #f "b")
]
Therefore, a catch-all type for @racket[regexp-match] is fairly large:
@racket[(Regexp String -> (U #f (Listof (U #f String))))].
Using this general type is cumbersome for simple patterns
where a match implies that all groups will successfully capture.
@racketblock[
> (define (get-domain (email : String)) : String
(cond
[(regexp-match #rx"(.*)@(.*)" email)
=> third]
[else "Match Failed"]))
]
@exact|{
\vspace{-1mm}%
$\!\!$\evalsto\RktErr{Type Error: expected String, got (U \#false String)}%
\vspace{1mm}
}|
We alleviate the need for casts and guards in simple patterns
with a parentheses-counting
interpretation that parses regular expressions
and returns the number of groups.
If there is any doubt whether a group will capture, we default to the general
@racket[regexp-match] type.
@exact|{
\hfill\fbox{$\RktMeta{rx->groups} \in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (rx->groups #rx"(a)(b)(c)")
==> 3
> (rx->groups #rx"((a)b)")
==> 2
> (rx->groups #rx"(a)*(b)")
==> #false
]
The corresponding elaboration
inserts casts to subtype the result of calls to @racket[regexp-match].
It also raises syntax errors when an uncompiled regular expression contains
unmatched parentheses.
@exact|{
\vspace{1mm}
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> '(regexp-match #rx"(a)b" str)
==> '((regexp-match #rx"(a)b" str)
:: (U #f (List String String)))
> '(regexp-match "(" str)
==>
]
@; =============================================================================
@section{Anonymous Functions}
By tokenizing symbolic λ-expressions, we can statically infer their domain.
@exact|{
\hfill\fbox{$\RktMeta{fun->domain} \in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (fun->domain '(λ (x y z)
(x (z y) y)))
==> '[Any Any Any]
> (fun->domain '(λ ([x : Real] [y : Real])
x))
==> '[Real Real]
]
When domain information is available at calls to a @racket[curry] function,
we elaborate to a type-correct, indexed version of @racket[curry].
Conceptually, we give @racket[curry] the unusable type @racket[( -> )] and
elaboration produces a subtype @racket[curry_i].
@exact|{
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> '(curry (λ (x y) x))
==> '(curry_2 (λ (x y) x))
]
This same technique can be used to implement generalized @racket[map] in
languages without variable-arity polymorphism@~cite[stf-esop-2009].
@racketblock[
> (define (cite (p : String) (d : String))
(printf "~a v. ~a, U.S.\n" p d))
> (define plaintiff*
'("Rasul" "Chisholm"))
> (define defendant*
'("Bush" "Georgia"))
> (map cite plaintiff* defendant*)
]
@exact|{
\vspace{-1mm}%
$\!\!$\evalsto\RktOut{Rasul v. Bush, U.S.}\\
$\hphantom{xxxxx}$\RktOut{Chisholm v. Georgia, U.S.}
\vspace{1mm}
}|
Leaving out an argument to @racket[printf] or passing an extra list
when calling @racket[map] will raise an arity error during elaboration.
On the other hand, if we modified @racket[cite] to take a third argument
then the above call to @racket[map] would raise a type error.
@; =============================================================================
@section{Numeric Constants}
The identity interpretation @exact{$\RktMeta{id} \in \interp$}
lifts values to the elaboration environment.
When composed with a filter, we can recognize types of compile-time constants.
@exact|{
\hfill\fbox{$\RktMeta{int?} \circ \RktMeta{id} = \RktMeta{int?} \in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (int? 2)
==> 2
> (int? "~s")
==> #false
]
Constant-folding versions of arithmetic operators are now easy to define
in terms of the built-in operations.
Our implementation re-uses a single fold/elaborate loop to make
textualist wrappers over @racket[+], @racket[expt] and others.
@exact|{
\vspace{2mm}
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> (define a ⟦3⟧)
> (define b (/ 1 (- a a)))
]
@exact|{
\vspace{-1mm}%
$\!\!$\evalsto\RktErr{Error: division by zero}%
\vspace{1mm}
}|
Partial folds also work as expected.
@racketblock[
> (* 2 3 7 z)
==> '(* 42 z)
]
Taken alone, this re-implementation of constant folding in an earlier compiler
stage is not very exciting.
But since folded expressions propagate their result upwards to arbitrary
analyses, we can combine these elaborations with a size-aware vector library to
guard against index errors access at computed locations.
@; =============================================================================
@section[#:tag "sec:vector"]{Fixed-Length Structures}
Fixed-length data structures are often initialized with a constant or
computed-constant length.
Racket's vectors are one such structure.
For each built-in vector constructor, we thus define an interpretation:
@exact|{
\vspace{2mm}
\hfill\fbox{$\RktMeta{vector->size} \in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (vector->size '#(0 1 2))
==> 3
> (vector->size '(make-vector 100))
==> 100
> (vector->size '(make-vector (/ 12 3)))
==> 4
]
After interpreting, we associate the size with the new vector at compile-time.
Other elaborators can use and propagate these sizes; for instance, we have
implemented elaborating layers for 13 standard vector operations.
Together, they constitute a length-aware vector library that serves as a
drop-in replacement for existing code.
If size information is ever missing, the operators silently default
to Typed Racket's behavior.
@exact|{
\vspace{2mm}
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> (vector-ref (make-vector 3) (+ 2 2))
==>
> (vector-length (vector-append '#(A B) '#(C D)))
==> 4
> (vector-ref (vector-map add1 '#(3 3 3)) 0)
==> (unsafe-ref (vector-map add1 '#(3 3 3)) 0)
]
For the most part, these elaborations simply manage sizes and
delegate the main work to Typed Racket vector operations.
We do, however, optimize vector references to unsafe primitives and
specialize operations like @racket[vector-length], as shown above.
@; =============================================================================
@section[#:tag "sec:sql"]{Database Schema}
Racket's @racket[db] library provides a string-based API for executing SQL
queries.@note{In this section, we use @tt{sql} as an abbreviation for @tt{postgresql}.}
After connecting to a database, SQL queries embedded in strings can be run
to retrieve row values, represented as Racket vectors.
Queries may optionally contain @emph{query parameters}---natural numbers
prefixed by a dollar sign (@tt{$}).
Arguments substituted for query parameters are guarded against SQL injection.
@exact|{
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{define}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{C}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{sql{-}connect}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{\#{\hbox{\texttt{:}}}user}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"admin"}
\mbox{\hphantom{\Scribtexttt{xxxxxxxxxxxxxxxxxxxxxxxxx}}}\RktPn{\#{\hbox{\texttt{:}}}database}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SCOTUS"}\RktPn{)}\RktPn{)}
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktPn{(}\RktSym{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{C}
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{"SELECT plaintiff FROM rulings}\\
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktVal{WHERE name = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{2001}\RktPn{)}
\evalsto\RktVal{\#}\RktVal{(}\RktVal{"Kyllo"}\RktVal{)}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
}|
This is a far cry from language-integrated query@~cite[mbb-sigmod-2006] or
Scala's LMS@~cite[ra-icfp-2015], but the interface
is relatively safe and very simple to use.
Typed Racket programmers may use the @racket[db] library by assigning
type signatures to functions like @racket[query-row].
This is somewhat tedious, as the distinct operations for querying one value,
one row, or a lazy sequence of rows need similar types.
A proper type signature might express the database library as a functor over the
database schema, but Typed Racket does not have functors or even existential types.
Even if it did, the queries-as-strings interface makes it impossible for a standard
type checker to infer type constraints on query parameters.
The situation worsens if the programmer uses multiple database connections.
One can either alias one query function to multiple identifiers (each with a specific type)
or weaken type signatures and manually type-cast query results.
@subsection{Phantom Types To the Rescue}
By associating a database schema with each connection, our elaboration technique
can provide a uniform solution to these issues.
We specialize both the input and output of calls to @racket[query-row],
helping catch bugs as early as possible.
Our solution, however, is not entirely annotation-free.
We need a schema representing the target database; for this, we ask
the programmer to supply an S-expression of symbols and types
that passes a @racket[schema?] predicate.
This approach is similar to phantom types@~cite[lm-dsl-1999].
@exact|{
\vspace{1mm}
\hfill\fbox{$\RktMeta{schema?} \in \interp$}
\vspace{-4mm}
}|
@racketblock[
> (define scotus-schema
'([decisions [(id . Natural)
(plaintiff . String)
(defendant . String)
(year . Natural)]]))
> (schema? scotus-schema)
==> '([decisions ....])
]
The above schema represents a database with at least one table, called @racket[decisions],
which contains at least 4 rows with the specified names and types.
In general a schema may specify any number of tables and rows.
We statically disallow access to unspecified ones in our elaborated query operations.
In addition to the @exact{$\RktMeta{schema?}$} predicate, we define one more
interpretation and two elaborations.
The first elaboration is for connecting to a database.
We require a statically-known schema object and elaborate to a normal connection.
@exact|{
\vspace{1mm}
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
}|
@racketblock[
> '(sql-connect #:user "admin"
#:database "SCOTUS")
==>
> '(sql-connect scotus-schema
#:user "admin"
#:database "SCOTUS")
==> '(sql-connect #:user "admin"
#:database "SCOTUS")
]
The next interpretation and elaboration are for reading constraints from
query strings.
We parse @tt{SELECT} statements using @racket[sql->constr] and extract
@itemlist[
@item{the names of selected columns,}
@item{the table name, and}
@item{an association from query parameters to column names.}
]
@exact|{
\vspace{1mm}
\hfill\fbox{$\RktMeta{sql->constr} \in \interp$}
\vspace{-4mm}
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT defendant FROM decisions}\\
\mbox{\hphantom{\Scribtexttt{xxxx}}}\RktVal{WHERE plaintiff = {\textquotesingle}\$1{\textquotesingle}"}
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{[}\RktVal{(}\RktVal{defendant}\RktVal{)}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{decisions}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{\$1}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{.}}} }\RktVal{plaintiff}\RktVal{)}\RktVal{]}
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT * FROM loans"}
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{[}\RktVal{*}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{decisions}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{(}\RktVal{)}\RktVal{]}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
}|
The schema, connection, and query constraints now come together in elaborations
such as @exact{$\RktMeta{query-exec} \in \elab$}.
There is still a non-trivial amount of work to be done resolving wildcards and
validating row names before the type-annotated result is produced,
but all the necessary information is available, statically.
@exact|{
\vspace{1mm}
\hfill\fbox{$\elabf \in \elab$}
\vspace{-4mm}
\begin{SCodeFlow}\begin{RktBlk}\begin{SingleColumn}\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{"SELECT plaintiff FROM decisions}\\
\mbox{\hphantom{\Scribtexttt{xxxxxxx}}}\RktVal{WHERE year = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
\mbox{\hphantom{\Scribtexttt{xxxxx}}}\RktVal{2006}\RktVal{)}\RktSym{$]\!]$}
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"SELECT {\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}"}
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{(}\RktVal{2006}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\RktVal{)}\RktVal{)}
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{{\hbox{\texttt{:}}}{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{xxx}}}\RktVal{(}\RktVal{Vector}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\RktVal{)}\RktVal{)}
\\
\\
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{"SELECT * FROM decisions}\\
\mbox{\hphantom{\Scribtexttt{xxxxxxx}}}\RktVal{WHERE plaintiff = {\textquotesingle}\$1{\textquotesingle} LIMIT 1"}
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"United States"}\RktVal{)}\RktSym{$]\!]$}
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{"SELECT {\hbox{\texttt{.}}}{\hbox{\texttt{.}}}{\hbox{\texttt{.}}}"}
\mbox{\hphantom{\Scribtexttt{xxxxxxxx}}}\RktVal{(}\RktVal{"United States"}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\RktVal{)}\RktVal{)}
\mbox{\hphantom{\Scribtexttt{xxxxxx}}}\RktVal{{\hbox{\texttt{:}}}{\hbox{\texttt{:}}}}\mbox{\hphantom{\Scribtexttt{xxx}}}\RktVal{(}\RktVal{Vector}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{String}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{Natural}\RktVal{)}\RktVal{)}
\\
\\
\RktSym{{\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$[\![$}\RktVal{{\textquotesingle}}\RktVal{(}\RktVal{query{-}row}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{C}\mbox{\hphantom{\Scribtexttt{x}}}\RktVal{"SELECT foo FROM decisions"}\RktVal{)}\RktSym{$]\!]$}
\RktSym{=={\Stttextmore}}\mbox{\hphantom{\Scribtexttt{x}}}\RktSym{$\perp$}\end{SingleColumn}\end{RktBlk}\end{SCodeFlow}
}|
Results produced by @racket[query-row] are vectors with a known length;
as such they cooperate with our library of vector operations described in
@Secref{sec:vector}.
Accessing a constant index into a row vector is statically guaranteed
to be in bounds.
@; casts can fail, especially if you wildcard without saying all the rows