$\displaystyle\mathcal{Q}=\int_{\operatorname{GL}_{n}(\mathbb{Q}_{p})}\psi_{p}\big{(}\operatorname{tr}(y)\big{)}I\big{(}\omega
y\big{)}dy$
$\displaystyle=\chi_{p}(\operatorname{det}\gamma)\int_{\omega^{-1}M}\psi_{p}\Big{(}\operatorname{tr}(y)\Big{)}I\Big{(}\omega
y\alpha^{-1}\Big{)}dy$
$\displaystyle=\chi_{p}(\det\gamma)\int_{\omega^{-1}M}\psi_{p}\Big{(}\operatorname{tr}(x\gamma)\Big{)}\psi_{p}\Big{(}\operatorname{tr}(x\delta)\Big{)}I\big{(}\omega
x\big{)}dx,$

where we make the change of variables $x=y\alpha^{-1}$. If
$x\in\operatorname{GL}_{n}(\mathbf{Q}_{p})$ it is easy to see that
$\delta\mapsto\psi_{p}(\operatorname{tr}(x\delta))$ is the trivial function of
$B_{\beta}$ if and only if

$x_{i,j}\in\left\\{\begin{array}[]{cc}p^{-\beta}\mathbb{Z}_{p}&\text{ if
}i<j\\\ \mathbb{Z}_{p}&\text{ if }i>j\end{array}\right.$

Denote this subset of $\operatorname{GL}_{n}(\mathbb{Q}_{p})$ by
$M_{\beta}^{\prime}$. Averaging over $B_{\beta}$, by character orthogonality
(as in [BDG+, Cor. 5.5]) we find

$\mathcal{Q}=\chi_{p}(\operatorname{det}\gamma)\int_{\omega^{-1}M\cap
M_{\beta}^{\prime}}\psi_{p}(\operatorname{tr}(x\gamma))I(\omega x)dx.$

Now we average over $A$. Consider the function

$\chi_{p}(\operatorname{det}\gamma)\psi_{p}(\operatorname{tr}(x\gamma))=\prod_{i=1}^{n}\chi_{p}(c_{i,i})\psi_{p}(x_{i,i}c_{i,i})$

Exactly following [BDG+, Lem. 5.6], we see that

$\Big{[}\int_{\gamma\in
A}\chi_{p}(\operatorname{det}\gamma)\psi_{p}(\operatorname{tr}(x\gamma))d^{\times}A\neq
0\Big{]}\iff\Big{[}x_{i,i}\in p^{-\beta}\mathbb{Z}_{p}^{\times}\text{ for all
}i\Big{]},$ (9.4)

and when the left-hand side is non-zero, it has form
$(\star^{\prime})\prod_{i=1}^{n}\chi_{p}(p^{\beta}x_{i,i})^{-1}$, with
$(\star^{\prime})\neq 0$ a scalar depending only on $\chi,p$ and $\beta$.

Let $M_{\beta}^{\prime\prime}\subset M_{\beta}^{\prime}$ be the subset where
the right-hand condition of (9.4) is satisfied. Note that
$M_{\beta}^{\prime\prime}=p^{-\beta}\operatorname{Iw}_{n}(p^{\beta})$. We then
have

$\mathcal{Q}=(\star^{\prime\prime})\int_{\omega^{-1}M\cap
M_{\beta}^{\prime\prime}}\prod_{i=1}^{n}\chi_{p}(p^{\beta}x_{i,i})^{-1}\cdot
I(\omega x)dx,\qquad(\star^{\prime\prime})\neq 0.$

Write $x^{\prime}=p^{\beta}x$ for $x\in\omega^{-1}M\cap
M_{\beta}^{\prime\prime}$. Then
$\chi_{p}(\operatorname{det}x^{\prime})=\prod_{i=1}^{n}\chi_{p}(p^{\beta}x_{i,i})$,
as $\chi_{p}$ has conductor $p^{\beta}$. If
$\nu=\nu_{\beta}(t)=-p^{-\beta}\omega,$ then we find

$\displaystyle\mathcal{Q}$
$\displaystyle=(\star^{\prime\prime})\int_{\omega^{-1}M\cap
M_{\beta}^{\prime\prime}}\chi_{p}(\det
p^{\beta}x)^{-1}I(-p^{\beta}x)dx=\int_{\nu^{-1}M\cap\mathrm{Iw}(p^{\beta})}\chi(\det
x^{\prime})^{-1}I(-\nu x^{\prime})dx^{\prime}$
$\displaystyle=(\star^{\prime\prime})\int_{\nu^{-1}M\cap\operatorname{Iw}_{n}(p^{\beta})}\chi_{p}(\det
x^{\prime})^{-1}W_{\varphi_{p}}\begin{pmatrix}-\nu x^{\prime}&\\\
&1\end{pmatrix}\chi_{p}|\cdot|^{s-\tfrac{1}{2}}(\det-\nu
x^{\prime})dx^{\prime}$
$\displaystyle=(\star^{\prime\prime})\chi_{p}|\cdot|^{s-\tfrac{1}{2}}(\det-\nu)\int_{\nu^{-1}M\cap\operatorname{Iw}_{n}(p^{\beta})}W_{\varphi_{p}}\begin{pmatrix}\nu&\\\
&1\end{pmatrix}dx^{\prime}$
$\displaystyle=(\star^{\prime\prime\prime})\operatorname{Vol}(\nu^{-1}M\cap\operatorname{Iw}_{n}(p^{\beta}))\cdot
W_{\varphi_{p}}\begin{pmatrix}\nu&\\\ &1\end{pmatrix},$ (9.5)

where $(\star^{\prime\prime\prime})\neq 0$ depends only on $\chi$, $t$, $p$,
and $s$. In the penultimate equality we use Iwahori-invariance of
$W_{\varphi_{p}}$.

We consider two cases:

  1. (1)

If $\nu\not\in M$, then $W_{\varphi_{p}}\left(\begin{smallmatrix}\nu&\\\
&1\end{smallmatrix}\right)=0$, thus $\mathcal{Q}=0$. In particular, both sides
of (9.1) are 0, so Proposition 9.1 holds.

  2. (2)

If $\nu\in M$, then $\nu\operatorname{Iw}_{n}(p^{\beta})$ is a compact open
subset of $\operatorname{GL}_{n}(\mathbb{Q}_{p})$, and it is contained in $M$.
This means $\operatorname{Iw}_{n}(p^{\beta})\subset\nu^{-1}M$, so the volume
above is $\operatorname{Vol}(\operatorname{Iw}_{n}(p^{\beta}))$ which is non-
zero. Then Proposition 9.1 follows from (9.5). ∎

######  Corollary 9.2.

If $\zeta_{p}(ut\cdot\varphi_{p},\chi_{p},s_{0})\neq 0$ for some
$s_{0}\in\mathbf{C}$, then $\zeta_{p}(ut\cdot\varphi_{p},\chi_{p},s)\neq 0$
for _all_ $s\in\mathbf{C}$.

###### Proof.

Non-vanishing of $W_{\varphi_{p}}\left(\begin{smallmatrix}\nu_{\beta}(t)&\\\
&1\end{smallmatrix}\right)$ is independent of $s$. ∎

######  Corollary 9.3.

If $P$ is a spin parabolic and $P$ is not contained in the $(n,n)$-parabolic,
then for all $\varphi_{p}\in\pi_{p}^{\mathrm{Iw}_{G}}$ and $s\in\mathbf{C}$,
we have

$\zeta_{p}(ut_{P}^{\beta}\cdot\varphi_{p},\chi_{p},s)=0.$

In particular, $Z_{H}(ut_{P}^{\beta}\cdot\varphi,\chi,s)=0$ for all
$\varphi=\otimes_{v}\varphi_{v}\in\pi^{\mathrm{Iw}_{G}}$.

###### Proof.

We apply Proposition 9.1 with $t=t_{P}^{\beta}$, which we write as
$\left(\begin{smallmatrix}z_{1}&\\\ &z_{2}\end{smallmatrix}\right)$ as above.

Suppose $P$ has type $(n_{1},...,n_{k})$. As $P$ is spin, $(n_{1},...,n_{k})$
is symmetric, whence

$t_{P}=p^{k-1}w_{2n}t_{P}^{-1}w_{2n}.$ (9.6)

Equation (9.6) implies that $z_{2}=p^{\beta(k-1)}w_{n}z_{1}^{-1}w_{n}$. Thus,
for $\nu_{\beta}(t_{P}^{\beta})$ as above, we have

$\nu_{\beta}(t_{P}^{\beta})=p^{-\beta}z_{2}^{-1}w_{n}z_{1}=p^{-\beta
k}w_{n}z_{1}^{2}.$ (9.7)

Let $[k/2]$ be the floor of $k/2$. Then $p^{2\beta[k/2]}$ is the largest power
of $p$ which divides $z_{1}^{2}$ (so that one remains in
$M_{n}(\mathbf{Z}_{p})$). Hence $\nu_{\beta}(t_{P}^{\beta})\in
M_{n}(\mathbf{Z}_{p})$ if and only if $k$ is even. As $P$ is spin, this
happens if and only if $P$ is contained in the $(n,n)$-parabolic. Since (by
[BDG+, Lem. 5.1]) the support of
$W_{\varphi_{p}}\left(\begin{smallmatrix}y&\\\ &1\end{smallmatrix}\right)$ is
in $M\subset M_{n}(\mathbf{Z}_{p})$, the first statement follows by
Proposition 9.1. The second follows from the arguments of §8.3. ∎

#### 9.2. Non-vanishing for $P$-spin eigenvectors

Let $\tilde{\pi}^{P}$ be a $P$-spin $P$-refinement. Suppose $P\subset Q$, the
$(n,n)$-parabolic. We now construct $\varphi_{p}\in\tilde{\pi}_{p}^{P}$ such
that $W_{\varphi_{p}}\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)\neq 0$.

##### 9.2.1. Explicit eigenvectors

We first give eigenvectors in principal series representations, generalising
[BDG+, §7.1]. Throughout $\pi_{p}=\operatorname{Ind}_{B}^{G}\theta$ is
irreducible and regular, with $\theta$ spin.

We recap (but slightly modify) some notation from [BDG+]. Let
$\mathcal{W}_{n}$ be the Weyl group of $\operatorname{GL}_{n}$. From now on we
always view Weyl elements of $\mathcal{W}_{G}$ (resp. $\mathcal{W}_{n}$) as
elements of $G(\mathbb{Z}_{p})$ (resp.
$\operatorname{GL}_{n}(\mathbb{Z}_{p})$). Recall $w_{n}$ is the longest
element in $\mathcal{W}_{n}$, and $\tau=\left(\begin{smallmatrix}1&\\\
&w_{n}\end{smallmatrix}\right)\in\mathcal{W}_{G}$.

  * •

For any $w,\nu\in\mathcal{W}_{G}$, let
$f^{\nu}_{w}\in\operatorname{Ind}_{B}^{G}\theta^{\nu}$ be the (unique)
Iwahori-invariant function supported on
$B(\mathbb{Q}_{p})w\operatorname{Iw}_{G}$ with $f_{w}^{\nu}(w)=p^{n(n-1)}$.

  * •

For $\rho\in\mathcal{W}_{n}$, let $w(\rho)=\left(\begin{smallmatrix}&w_{n}\\\
\rho&\end{smallmatrix}\right)$, and (noting the difference to [BDG+, Def.
7.6]) let

$F^{\nu}_{\rho}=f^{\nu}_{w(\rho)}\in\operatorname{Ind}_{B}^{G}(\theta^{\nu}).$

The relevance of these vectors is captured by [BDG+, Prop. 7.4], where we
showed:

######  Proposition 9.4.

Let
$\tilde{\pi}_{\nu}=(\pi,\alpha_{\nu})\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\Psi_{\theta}^{-1}(\nu)$.
Then
$f_{w_{2n}}^{\nu}=F_{w_{n}}^{\nu}\in\operatorname{Ind}_{B}^{G}\theta^{\nu}$ is
an Iwahori-invariant $\alpha_{\nu}$-eigenvector.

We now define parahoric-level analogues. Recall $\mathcal{W}_{L_{P}}$ is the
Weyl group of the levi $L_{P}$ of $P$. For $w\in\mathcal{W}_{G}$, let
$[w]\in\mathcal{W}_{G}/\mathcal{W}_{L_{P}}$ denote the corresponding coset.

Since $P\subset Q$, it is a $(k_{1},\dots,k_{r},k_{r},\dots,k_{1})$-parabolic
for some $k_{i}$ with $k_{1}+\dots+k_{r}=n$. Let
$\mathcal{W}_{\mathbf{k}}\subset\mathcal{W}_{n}$ denote the Weyl group
associated with the Levi of the $(k_{1},\dots,k_{r})$-parabolic in
$\operatorname{GL}_{n}$. For $\rho\in\mathcal{W}_{n}$, let
$[\rho]^{\prime}\in\mathcal{W}_{n}/\mathcal{W}_{\mathbf{k}}$ denote the
corresponding coset.

  * •

For $w,\nu\in\mathcal{W}_{G}$, let
$h^{\nu}_{[w]}\in\operatorname{Ind}_{B}^{G}\theta^{\nu}$ denote the
$J_{P}$-invariant function supported on $B(\mathbb{Q}_{p})wJ_{P}$ normalised
so that $h^{\nu}_{[w]}(w)=p^{n(n-1)}$. Writing $B(\mathbf{Q}_{p})wJ_{P}$ as a
union of sets of the form $B(\mathbf{Q}_{p})w^{\prime}\operatorname{Iw}_{G}$,
we have

$h^{\nu}_{[w]}=\sum_{w^{\prime}\in\mathcal{W}_{G},\
[w^{\prime}]=[w]}f^{\nu}_{w^{\prime}}.$

In particular, $h^{\nu}_{[w]}=h^{\nu}_{[w^{\prime}]}$ if $[w]=[w^{\prime}]$.

  * •

For $\rho\in\mathcal{W}_{n}$, we set

$H^{\nu}_{[\rho]^{\prime}}=h^{\nu}_{[w(\rho)]}.$

######  Proposition 9.5.

Let
$\tilde{\pi}_{\nu}^{P}=(\pi,\alpha_{\nu}^{P})\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=(\Psi_{\theta}^{P})^{-1}([\nu])$.
Then
$h_{[w_{2n}]}^{\nu}=H_{[w_{n}]^{\prime}}^{\nu}\in\operatorname{Ind}_{B}^{G}\theta^{\nu}$
is a $J_{P}$-invariant $\alpha_{\nu}^{P}$-eigenvector.

###### Proof.

Identical to [BDG+, Prop. 7.4] or [DJR20, Lem. 3.6]. ∎

If $\nu=1$, we drop the superscript $\nu$, and simply write
$f_{w},F_{\rho},h_{[w]},H_{[\rho]^{\prime}}$.

We return to our fixed $P$-spin $P$-refinement
$\tilde{\pi}^{P}=(\pi,\alpha^{P})$.

######  Lemma 9.6.

We may choose a spin $\theta$ so that
$\varphi_{p}\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=H_{[w_{n}]^{\prime}}\in\tilde{\pi}_{p}^{P}$
is an $\alpha^{P}$-eigenvector.

###### Proof.

By definition
$\Psi_{\theta}^{P}(\tilde{\pi}^{P})=[\sigma]\in\mathcal{W}_{G}/\mathcal{W}_{L_{P}},$
for some $\sigma\in\mathcal{W}_{G}^{0}$. After renormalising $\theta$ by
$\sigma$ (as in Remarks 2.11 and 3.3) we may assume $\sigma=1$; as
$\sigma\in\mathcal{W}_{G}^{0}$ such a $\theta$ is still spin by Definition
2.7. The result follows from Proposition 9.5. ∎

##### 9.2.2. Intertwining maps

We now have an eigenvector
$H_{[w_{n}]^{\prime}}\in\operatorname{Ind}_{B}^{G}\theta$. To transfer this
into the Shalika model $\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\tilde{\pi}_{p})$,
we must write down an explicit Shalika intertwining.

If $\Theta$ is an unramified character satisfying
$\Theta_{i}\Theta_{n+i}=\eta_{p}$ for all $i$, Ash–Ginzburg [AG94, (1.3)] have
constructed such an explicit
$\mathcal{S}:\operatorname{Ind}_{B}^{G}\Theta\to\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\pi_{p})$,
given by

$\mathcal{S}(f)(g)\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\int_{\operatorname{GL}_{n}(\mathbf{Z}_{p})}\int_{M_{n}(\mathbf{Q}_{p})}f\left[\left(\begin{smallmatrix}&1\\\
1&\end{smallmatrix}\right)\left(\begin{smallmatrix}1&X\\\
&1\end{smallmatrix}\right)\left(\begin{smallmatrix}k&\\\
&k\end{smallmatrix}\right)g\right]\psi^{-1}(\mathrm{tr}(X))\eta^{-1}(\det(k))dXdk.$
(9.8)

Here we encounter a problem: our choice of $\theta$ does not satisfy the
Ash–Ginzburg condition; rather, $\theta^{\tau}$ does, where
$\tau=\mathrm{diag}(1,w_{n})$. We know $\operatorname{Ind}_{B}^{G}\theta$ and
$\operatorname{Ind}_{B}^{G}\theta^{\tau}$ are isomorphic, but to use (9.8), we
must compute what this isomorphism does to the eigenvector $\varphi_{p}$ from
Lemma 9.6. We do so by generalising [BDG+, §7.3], using work of Casselman.

Let $\nu=\left(\begin{smallmatrix}1&\\\
&\nu^{\prime}\end{smallmatrix}\right)\in\mathcal{W}_{G}$ and
$s=\left(\begin{smallmatrix}1&\\\
&s^{\prime}\end{smallmatrix}\right)\in\mathcal{W}_{G}$ be a simple reflection.
Suppose that $s$ corresponds to the simple transposition $(a,a+1)$ for
$a\geqslant n+1$. Set
$\theta(s)\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\theta_{a}(p)/\theta_{a+1}(p)$
and

$c_{s}(\theta^{\nu})\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\frac{1-p^{-1}\theta^{\nu}(s)}{1-\theta^{\nu}(s)}.$
(9.9)

Note $c_{s}(\theta^{\nu})$ is well-defined as $\theta^{\nu}$ is regular, and
_always_ non-zero as $\operatorname{Ind}_{B}^{G}\theta^{\nu}$ is irreducible.

Let $l$ denote the Bruhat length function on $\mathcal{W}_{G}$. Then Casselman
[Cas80, Thm. 3.4] shows that there are intertwinings
$T^{\nu}_{s}\colon\operatorname{Ind}_{B}^{G}\theta^{\nu}\to\operatorname{Ind}_{B}^{G}\theta^{\nu
s^{-1}}$ with the following property:

$T^{\nu}_{s}(f^{\nu}_{w})=\left\\{\begin{array}[]{cc}p^{-1}f^{\nu
s^{-1}}_{sw}+(c_{s}(\theta^{\nu})-1)f^{\nu s^{-1}}_{w}&\text{ if
}l(sw)>l(w)\\\ f^{\nu s^{-1}}_{sw}+(c_{s}(\theta^{\nu})-p^{-1})f_{w}^{\nu
s^{-1}}&\text{ if }l(sw)<l(w)\end{array}\right.$ (9.10)

The eigenvector $H_{[w_{n}]^{\prime}}$ is a _sum_ of $f_{w}^{\nu}$’s as $w$
ranges over a coset in $\mathcal{W}_{G}/\mathcal{W}_{L_{P}}$. The following
allows us to apply a case of (9.10) consistently to $f_{w}^{\nu}$ for every
$w$ in a $\mathcal{W}_{L_{P}}$-coset.

######  Lemma 9.7.

Let $s\in\mathcal{W}_{G}$ be a simple reflection, and let
$w\in\mathcal{W}_{G}$. Then exactly only one of the following possibilities
can occur:

  1. (1)

$sw\mathcal{W}_{L_{P}}=w\mathcal{W}_{L_{P}}$, whence left multiplication by
$s$ permutes $w\mathcal{W}_{L_{P}}$;

  2. (2)

$sw\mathcal{W}_{L_{P}}\neq w\mathcal{W}_{L_{P}}$ and $l(sv)<l(v)$ for all
$v\in w\mathcal{W}_{L_{P}}$;

  3. (3)

$sw\mathcal{W}_{L_{P}}\neq w\mathcal{W}_{L_{P}}$ and $l(sv)>l(v)$ for all
$v\in w\mathcal{W}_{L_{P}}$.

###### Proof.

If $sw\mathcal{W}_{L_{P}}=w\mathcal{W}_{L_{P}}$, (1) occurs; so suppose
$sw\mathcal{W}_{L_{P}}\neq w\mathcal{W}_{L_{P}}$.

Let $w_{\operatorname{min}}$ and $v_{\operatorname{min}}$ be the unique
minimal length representatives in $w\mathcal{W}_{L_{P}}$ and
$sw\mathcal{W}_{L_{P}}$ respectively; properties of such elements are
described in [Hum90, §1.10]. As $s$ is simple, we must have
$l(sw_{\min})=l(w_{\min})\pm 1$; so we have two possibilities:

Possibility 1:
$l(sw_{\operatorname{min}})=l(w_{\min})-1<l(w_{\operatorname{min}})$.

As $sw_{\min}\in sw\mathcal{W}_{L_{P}}$, there is a unique
$x\in\mathcal{W}_{L_{P}}$ such that
$sw_{\operatorname{min}}=v_{\operatorname{min}}\cdot x$. We have
$l(sw_{\operatorname{min}})=l(v_{\operatorname{min}})+l(x)$. As $l(x)\geqslant
0$, we have

$l(v_{\operatorname{min}})\leqslant l(sw_{\min})<l(w_{\operatorname{min}}).$
(9.11)

On the other hand, we can write $v_{\operatorname{min}}=sy$ for some $y\in
w\mathcal{W}_{L_{P}}$. Again, we either have
$l(v_{\operatorname{min}})=l(y)\pm 1$. We also have
$l(w_{\operatorname{min}})\leqslant l(y)$ by minimality of
$l(w_{\operatorname{min}})$. If $l(v_{\min})=l(y)+1$, then
$l(w_{\operatorname{min}})\leqslant l(y)<l(v_{\operatorname{min}})$,
contradicting (9.11). Hence $l(v_{\operatorname{min}})=l(y)-1$. But then

$l(v_{\min})<l(w_{\operatorname{min}})\leqslant
l(y)=l(v_{\operatorname{min}})+1.$

This can only happen if $l(y)=l(w_{\operatorname{min}})=l(v_{\min})+1$.
Therefore $y=w_{\operatorname{min}}$ (by uniqueness of the minimal length
representative), and $v_{\operatorname{min}}=sw_{\operatorname{min}}$.

Now take any $v\in w\mathcal{W}_{L_{P}}$. There are unique
$X,Y\in\mathcal{W}_{L_{P}}$ such that $v=w_{\operatorname{min}}X$ and
$sv=v_{\operatorname{min}}Y=sw_{\operatorname{min}}Y$. By uniqueness, we must
have $X=Y$. Finally, we now see that

$l(sv)=l(sw_{\operatorname{min}})+l(X)<l(w_{\operatorname{min}})+l(X)=l(v),$

so we are in case (2) of the Lemma.

Possibility 2:
$l(sw_{\operatorname{min}})=l(w_{\min})+1>l(w_{\operatorname{min}})$.

We break this up into three further cases:

  * (a)

If $l(v_{\operatorname{min}})>l(w_{\operatorname{min}})$, then we must have
$l(v_{\operatorname{min}})\geqslant l(sw_{\operatorname{min}})$. Minimality of
$l(v_{\min})$ forces equality, hence
$v_{\operatorname{min}}=sw_{\operatorname{min}}$ by uniqueness of the minimal
length representative. Then if $v\in w\mathcal{W}_{L_{P}}$, as above we must
have $v=w_{\operatorname{min}}X$ and $sv=sw_{\operatorname{min}}X$ for some
(unique) $X\in\mathcal{W}_{L_{P}}$. Hence for any $v\in w\mathcal{W}_{L_{P}}$,
we have

$l(sv)=l(sw_{\operatorname{min}})+l(X)>l(w_{\operatorname{min}})+l(X)=l(v),$

whence we are in case (3) of the lemma.

  * (b)

If $l(v_{\operatorname{min}})=l(w_{\operatorname{min}})$, then let
$w_{\operatorname{min}}=s_{1}\cdots s_{r}$ and
$v_{\operatorname{min}}=s_{1}^{\prime}\cdots s_{r}^{\prime}$ be reduced word
expressions for these elements. We can write
$sw_{\operatorname{min}}=v_{\operatorname{min}}\cdot t$ for some unique
$t\in\mathcal{W}_{L_{P}}$. Moreover, since
$l(v_{\operatorname{min}})+l(t)=l(sw_{\operatorname{min}})=l(w_{\operatorname{min}})+1$,
we see that $l(t)=1$ and hence $t$ is simple. We must therefore have
$w_{\operatorname{min}}<sw_{\operatorname{min}}=v_{\operatorname{min}}t$ in
the (strong) Bruhat order.

Since $s_{1}^{\prime}\cdots s_{r}^{\prime}t$ is a reduced word for
$v_{\operatorname{min}}t$, we find that $s_{1}\cdots s_{r}$ occurs inside this
word. If

$s_{1}\cdots s_{r}=s_{1}^{\prime}\cdots\hat{s}_{i}^{\prime}\cdots
s^{\prime}_{r}t$

where $\hat{\cdot}$ denotes omission of the term, then we see that
$w_{\operatorname{min}}\in s_{1}^{\prime}\cdots\hat{s}_{i}^{\prime}\cdots
s^{\prime}_{r}\mathcal{W}_{L_{P}}$, which contradicts the fact that
$w_{\operatorname{min}}$ is a minimal length representative. Hence we must
have $s_{1}\cdots s_{r}=s_{1}^{\prime}\cdots s_{r}^{\prime}$, hence
$w_{\operatorname{min}}=v_{\operatorname{min}}$. But this contradicts the
assumption that $sw\mathcal{W}_{L_{P}}\neq w\mathcal{W}_{L_{P}}$. So this case
can never occur.

  * (c)

If $l(v_{\operatorname{min}})<l(w_{\operatorname{min}})$, then write
$v_{\operatorname{min}}=sy$ for some $y\in w\mathcal{W}_{L_{P}}$. Arguing as
in Possibility 1, this would imply $y=w_{\operatorname{min}}$, hence
$l(sw_{\operatorname{min}})<l(w_{\operatorname{min}})$, which is a
contradiction to the premise of Possibility 2. Thus (c) also never occurs.

Case (a) must thus occur, giving case (3) of the lemma, completing the proof.
∎

######  Lemma 9.8.

There exists an intertwining

$M_{\tau}\colon\operatorname{Ind}_{B}^{G}\theta\to\operatorname{Ind}_{B}^{G}\theta^{\tau}$

such that

$M_{\tau}(H_{[w_{n}]^{\prime}})=H^{\tau}_{[1]^{\prime}}+\sum_{\begin{subarray}{c}x\in\mathcal{W}_{n}/\mathcal{W}_{\mathbf{k}}\\\
x\neq[1]^{\prime}\end{subarray}}c_{x}H^{\tau}_{x}$

for some $c_{x}\in\mathbb{C}$ (note the sum may be empty).

###### Proof.

Let $\rho\in\mathcal{W}_{n}$, and $s=\left(\begin{smallmatrix}1&\\\
&s^{\prime}\end{smallmatrix}\right)\in\mathcal{W}_{G}$ a simple reflection. We
apply (9.10) in two cases:

  1. (1)

Suppose $sw(\rho)\mathcal{W}_{L_{P}}=w(\rho)\mathcal{W}_{L_{P}}$. Then by
Lemma 9.7(1), there exist $w_{1},\dots,w_{b}\in w(\rho)\mathcal{W}_{L_{p}}$
such that

$w(\rho)\mathcal{W}_{L_{p}}=\\{w_{1},\dots,w_{b},sw_{1},\dots,sw_{b}\\}$

with all the elements in the set distinct. Then we have

$T^{\nu}_{s}(f^{\nu}_{w_{i}}+f^{\nu}_{sw_{i}})=c_{s}(\theta^{\nu})(f^{\nu
s^{-1}}_{w_{i}}+f^{\nu s^{-1}}_{sw_{i}})$

hence $T^{\nu}_{s}(H^{\nu}_{[\rho]^{\prime}})=c_{s}(\theta^{\nu})H^{\nu
s^{-1}}_{[\rho]^{\prime}}$.

  2. (2)

Suppose $sw(\rho)\mathcal{W}_{L_{P}}\neq w(\rho)\mathcal{W}_{L_{P}}$. Then by
parts (2) and (3) in Lemma 9.7, we have

$T^{\nu}_{s}(H^{\nu}_{[\rho]^{\prime}})=\left\\{\begin{array}[]{cc}p^{-1}H^{\nu
s^{-1}}_{[s^{\prime}\rho]^{\prime}}+(c_{s}(\theta^{\nu})-1)H^{\nu
s^{-1}}_{[\rho]^{\prime}}&\text{ if }l(sw(\rho))>l(w(\rho))\\\ H^{\nu
s^{-1}}_{[s^{\prime}\rho]^{\prime}}+(c_{s}(\theta^{\nu})-p^{-1})H_{[\rho]^{\prime}}^{\nu
s^{-1}}&\text{ if }l(sw(\rho))<l(w(\rho)).\end{array}\right.$

Crucially the only terms that appear here are of the form $H_{x}^{\nu s^{-1}}$
for $x\in\mathcal{W}_{n}/\mathcal{W}_{\mathbf{k}}$.

Now write $w_{n}=s^{\prime}_{1}\cdots s_{c}^{\prime}$, so
$\tau=s_{c}^{-1}\cdots s_{1}^{-1}$ with $s_{i}=\left(\begin{smallmatrix}1&\\\
&s_{i}^{\prime}\end{smallmatrix}\right)$. We may assume that the factorisation
of $w_{n}$ is chosen such that $s_{c}^{\prime}\cdots s_{b+1}^{\prime}$ is the
minimal length representative of the coset
$w_{n}\mathcal{W}_{\mathbf{k}}\subset\mathcal{W}_{n}$ and $s_{i}^{\prime}$
($i=1,\dots,b$) are simple reflections in $\mathcal{W}_{\mathbf{k}}$, for some
integer $1\leqslant b\leqslant c$. Composing, we have

$M_{\tau}=T^{s_{c}^{-1}\cdots s_{2}^{-1}}_{s_{1}}\circ\cdots\circ
T^{s_{c}^{-1}}_{s_{c-1}}\circ
T^{1}_{s_{c}}:\pi_{p}=\operatorname{Ind}_{B}^{G}\theta\longrightarrow\operatorname{Ind}_{B}^{G}(\theta^{\tau}).$

Iterating the formulae, we see $M_{\tau}(H_{[w_{n}]^{\prime}})$ is a linear
combination of $H^{\tau}_{x}$’s for
$x\in\mathcal{W}_{n}/\mathcal{W}_{\mathbf{k}}$. The coefficient of
$H_{[1]^{\prime}}^{\tau}$ is the product of
$\prod_{i=1}^{b}c_{s_{i}}(\theta^{s_{c}^{-1}\cdots s_{i+1}^{-1}})$ and a power
of $p$, and we saw after (9.9) that this product is non-zero. Therefore, we
may renormalise $M_{\tau}$ to make this coefficient equal to $1$. ∎

##### 9.2.3. Non-vanishing

With set-up as above, choose a spin $\theta$ so that
$H_{[w_{n}]^{\prime}}\in\operatorname{Ind}_{B}^{G}\theta$ is an eigenvector
for $\tilde{\pi}^{P}$. We now show that $H_{[w_{n}]^{\prime}}$ does not vanish
under the composition

$\operatorname{Ind}_{B}^{G}\theta\mathrel{\mathop{\xrightarrow{\qquad\qquad}}^{M_{\tau}}_{\text{Lemma
\ref{lem:casselman}}}}\operatorname{Ind}_{B}^{G}\theta^{\tau}\mathrel{\mathop{\xrightarrow{\qquad\qquad}}^{\mathcal{S}}_{\text{\eqref{eq:AG}}}}\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\pi_{p})\xrightarrow{\
\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)}\mathbf{C}.$

Write $t_{P}^{\beta}=\operatorname{diag}(z_{1},z_{2})$ as before. Recalling
$P$ is the $(k_{1},...,k_{r},k_{r},...,k_{1})$-parabolic, by (9.7) we have
$\nu_{\beta}(t_{P}^{\beta})=p^{-2\beta r}w_{n}z_{1}^{2}$, for $r$ as _op.
cit_. Note $z\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=p^{-\beta
r}z_{1}$ has coefficients in $\mathbb{Z}_{p}$ (as $P\subset Q$; see the proof
of Corollary 9.3).

######  Lemma 9.9.

(cf. [BDG+, Prop. 7.9]). Let $\delta\in\mathcal{W}_{n}$. We have

$\left(\begin{smallmatrix}&1\\\
1&\end{smallmatrix}\right)\left(\begin{smallmatrix}1&X\\\
&1\end{smallmatrix}\right)\left(\begin{smallmatrix}k&\\\
&k\end{smallmatrix}\right)\left(\begin{smallmatrix}w_{n}z^{2}&\\\
&1\end{smallmatrix}\right)\in
B(\mathbb{Q}_{p})\left(\begin{smallmatrix}&w_{n}\\\ \delta
w_{n}&\end{smallmatrix}\right)J_{P}$

if and only if:

  * •

$[\delta w_{n}]^{\prime}=[1]^{\prime}$,

  * •

$k\in B_{n}(\mathbb{Z}_{p})w_{n}J_{\mathbf{k}^{\prime}}$, where
$J_{\mathbf{k}^{\prime}}$ is the parahoric in $\operatorname{GL}_{n}$ of type
$\mathbf{k}^{\prime}=(k_{r},\dots,k_{1})$,

  * •

and $k^{-1}X\in w_{n}z^{2}M_{n}(\mathbb{Z}_{p})$.

###### Proof.

The proof closely follows that of [BDG+, Prop. 7.9], and we merely indicate
the small differences here. The “if” direction is identical to _op. cit_.

For the “only if” direction, we again start from (7.10) _op. cit_. (where now
the matrix $\left(\begin{smallmatrix}a&b\\\ c&d\end{smallmatrix}\right)$ is in
$J_{P}$). If we can show $[\delta w_{n}]^{\prime}=[1]^{\prime}$, then the
remaining conditions follow as in (1)–(4) following (7.10) _op. cit_. If
$P=Q$, then $[\delta w_{n}]^{\prime}=[1]^{\prime}$ is always satisfied.
Suppose then that $P\neq Q$ (hence $r>1$), and that $[\delta
w_{n}]^{\prime}\neq[1]^{\prime}$, i.e. $\delta
w_{n}\not\in\mathcal{W}_{\mathbf{k}}$.

We have the following analogue of Claim 7.12 _op. cit_.: let
$Y_{P}\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\\{k_{1},k_{1}+k_{2},...,k_{1}+\cdots+k_{r-1}\\}$.
Then $\mathcal{W}_{\mathbf{k}}=\cap_{m\in Y_{P}}\mathcal{W}_{(m,n-m)}$. Thus
$\delta w_{n}\not\in\mathcal{W}_{(m,n-m)}$ for some $m\in Y_{P}$, whence

$B_{n}(\mathbb{Q}_{p})\delta w_{n}\overline{J}_{m}\cap
B_{n}(\mathbb{Q}_{p})\overline{J}_{m}=\varnothing$ (9.12)

where $\overline{J}_{m}$ is the opposite parahoric in
$\operatorname{GL}_{n}(\mathbf{Z}_{p})$ of type $(m,n-m)$.

Now factorise $z^{2}=t_{p,m}\mu$. Via the same proof of the analogous
statement in [BDG+], we can show $kw_{n}\mu\in
B_{n}(\mathbb{Q}_{p})\overline{J}_{m}\cap B_{n}(\mathbb{Q}_{p})\delta
w_{n}\overline{J}_{m}$, a contradiction to (9.12). We deduce $[\delta
w_{n}]^{\prime}=[1]^{\prime}$, and hence the lemma. ∎

Recall $\tilde{\pi}^{P}=(\pi,\alpha^{P})$ is a $P$-spin $P$-refinement, with
$P\subset Q$. We finally obtain:

######  Proposition 9.10.

The element $\mathcal{S}(M_{\tau}(H_{[w_{n}]^{\prime}}))$ is an
$\alpha^{P}$-eigenvector in $\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\pi_{p})$, and

$\mathcal{S}(M_{\tau}(H_{[w_{n}]^{\prime}}))\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)\neq 0.$

###### Proof.

This is an $\alpha^{P}$-eigenvector by Lemma 9.6 and Hecke-equivariance of
$M_{\tau}$ and $\mathcal{S}$. Non-vanishing follows exactly the same proof as
[BDG+, Prop. 7.12]. Precisely, we show that

$\mathcal{S}(M_{\tau}(H_{[w_{n}]^{\prime}}))\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)=\mathcal{S}(H^{\tau}_{[1]^{\prime}})\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)\neq 0.$

Here the first equality holds as Lemma 9.8 expresses
$M_{\tau}(H_{[w_{n}]^{\prime}})$ as a linear combination of $H_{x}^{\tau}$’s,
and Lemma 9.9 shows that the the integrand of $\mathcal{S}$ (in (9.8))
vanishes on each of these except $H_{[1]^{\prime}}^{\tau}$. Non-vanishing is a
direct calculation. ∎

#### 9.3. Proof of Theorem 8.5

As in §8.3, it suffices to prove $(2^{\prime})\Rightarrow(1^{\prime})$ in
Conjecture 8.10; i.e. we must show there exists
$\varphi_{p}\in\tilde{\pi}^{P}$ such that
$\zeta_{p}(ut_{P}^{\beta}\cdot\varphi,\chi,s)\neq 0$. By Proposition 9.1, it
suffices to prove
$W_{\varphi_{p}}\left(\begin{smallmatrix}\nu_{\beta}(t_{P}^{\beta})&\\\
&1\end{smallmatrix}\right)\neq 0$, where
$W_{\varphi_{p}}=\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\varphi_{p})$ for some
Shalika intertwining $\mathcal{S}_{\psi_{p}}^{\eta_{p}}$. Since the
$\alpha^{P}$-eigenspaces in $\pi_{p}^{\mathrm{Iw}_{G}}$ and
$\mathcal{S}_{\psi_{p}}^{\eta_{p}}(\pi^{\mathrm{Iw}_{G}})$ are both
1-dimensional, it suffices to exhibit _any_ $\alpha^{P}$-eigenvector in the
Shalika model with this non-vanishing property. Such an eigenvector is given
by Proposition 9.10. ∎

### 10\. Proof of Theorem 8.6

Finally we use our study of the symplectic locus to prove a result towards the
remaining implication $(1)\Rightarrow(2)$ in Conjecture 8.4. If the hypotheses
of Theorem 8.6 are satisfied, this furnishes a ‘good’ choice of Iwahori
refinement $\tilde{\pi}$ above $\tilde{\pi}^{P}$. Key to our proof is:

######  Proposition 10.1.

Suppose (1) of Conjecture 8.4 holds. There is an $(\\#X_{P}+1)$-dimensional
symplectic family $\mathscr{C}$ through $\tilde{\pi}$ in the
$\operatorname{GL}_{2n}$-eigenvariety $\mathscr{E}_{K_{B}}^{G}$, varying over
$\mathscr{W}_{0,\lambda_{\pi}}^{P}$.

_Proof of Theorem 8.6, given Proposition 10.1:_ Suppose (1) is satisfied in
Conjecture 8.4. By Corollary 9.3, we see $P$ must be contained in the
$(n,n)$-parabolic. Further, as in §8.3, we deduce that
$L(\pi\times\chi,s+1/2)\neq 0$; that $\pi$ is symplectic; and that to deduce
(2) in Conjecture 8.4 it suffices to prove $\tilde{\pi}$ (hence
$\tilde{\pi}^{P}$) is $P$-spin.

Let
$\Omega\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=w(\mathscr{C})$,
open of maximal dimension in $\mathscr{W}_{0,\lambda_{\pi}}^{P}$. If
$\tilde{\pi}$ is not $P$-spin, then it is optimally $P^{\prime}$-spin for some
spin parabolic $P^{\prime}\not\subset P$. Then Theorem 4.9 shows that
$w(\mathscr{C})\subset\mathscr{W}_{0,\lambda_{\pi}}^{P^{\prime}}$, hence

$\Omega=w(\mathscr{C})\subset\mathscr{W}_{0,\lambda_{\pi}}^{P^{\prime}}\cap\Omega\subsetneq\Omega,$

a contradiction; so $\tilde{\pi}$ is $P$-spin. ∎

The proof of Proposition 10.1 occupies the rest of this section.

#### 10.1. Big evaluation maps: $p$-adic interpolation of branching laws

Our proof closely follows [BDG+, Thm. 13.6], which treated the case $P=B$; and
[BDW, Thm. 7.6(a–c)], which treated the analogous result in the
$(n,n)$-parabolic eigenvariety. These works constructed _evaluation maps_ on
overconvergent cohomology groups, over affinoids $\Omega$ in the weight space,
valued in torsion-free $\mathcal{O}_{\Omega}$-modules. Non-vanishing of these
maps puts strong constraints on the structure of the overconvergent
cohomology, and was shown to produce symplectic families in the eigenvariety.
We refer the reader to these works for any undefined notation.

Let $K=K^{p}K_{p}\subset G(\mathbf{A}_{f})$ be open compact, with
$K_{p}\subset J_{P}$ inside the $P$-parahoric subgroup. As in [BDW, §2.10],
choices at infinity fix for all $K$ (non-canonical) embeddings

$\pi_{f}^{K}\lhook\joinrel\relbar\joinrel\rightarrow\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{V}_{\lambda_{\pi}}^{\vee}(\overline{\mathbf{Q}}_{p}))_{\tilde{\pi}},\qquad\varphi\mapsto\phi_{\varphi},$
(10.1)

where the subscript $\tilde{\pi}$ denotes the $\tilde{\pi}$-eigenspace.

For a dominant weight $\lambda=(\lambda_{1},...,\lambda_{2n})$, let

$\mathrm{Crit}(\lambda)\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\\{j\in\mathbf{Z}:-\lambda_{n+1}\geqslant
j\geqslant-\lambda_{n}\\}.$

In [BDG+, §4], to the data of $\lambda,P,\chi,j\in\mathrm{Crit}(\lambda)$, and
$\eta=\eta_{0}|\cdot|^{{\sf w}(\lambda)}$ with $\eta_{0}$ finite order, we
constructed parahoric evaluation maps

$\mathcal{E}_{\lambda_{\pi},P,\chi}^{j,\eta_{0}}:\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{V}_{\lambda}^{\vee}(\overline{\mathbf{Q}}_{p}))\longrightarrow\overline{\mathbf{Q}}_{p}.$
(10.2)

Let $\varphi^{(p)}=\otimes_{\ell\neq p}\varphi_{\ell}^{\mathrm{FJ}}$, as in
§8.3. Then for any $\varphi_{p}\in\pi_{p}$, by [BDG+, Thm. 4.16] we have

$\mathcal{E}_{\lambda_{\pi},P,\chi}^{j,\eta_{0}}\left(\phi_{\varphi}\right)=A_{\lambda_{\pi},P,\chi}^{j}\cdot
L\Big{(}\pi\times\chi,j+\tfrac{1}{2}\Big{)}\cdot\zeta_{p}\Big{(}ut_{P}^{\beta}\cdot\varphi_{p},\chi_{p},j+\tfrac{1}{2}\Big{)},$
(10.3)

where $\varphi=\varphi^{(p)}\otimes\varphi_{p}\in\pi_{f}$ and
$A_{\lambda,P,\chi}^{j}$ is a non-zero scalar.

In the rest of §10.1 we will prove the following existence of a ‘big
evaluation map’, interpolating (10.2) as $\lambda$ varies over an
$(\\#X_{P}+1)$-dimensional affinoid
$\Omega=\mathrm{Sp}(\mathcal{O}_{\Omega})\subset\mathscr{W}_{0,\lambda_{\pi}}^{P}$,
which we henceforth fix.

######  Proposition 10.2.

Let $\beta\geqslant 1$, $\chi$ a Dirichlet character of conductor $p^{\beta}$,
$\eta_{0}$ a Dirichlet character, and $j\in\mathrm{Crit}(\lambda_{\pi})$. Then
for any classical $\lambda\in\Omega$, we have
$j_{\lambda}\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=j-{\sf
w}(\lambda-\lambda_{\pi})/2\in\mathrm{Crit}(\lambda)$, and there exists an
$\mathcal{O}_{\Omega}$-module map
$\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}:\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{D}_{\Omega}^{P})\to\mathcal{O}_{\Omega}$
such that for all classical $\lambda\in\Omega$, we have a commutative diagram

$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{D}_{\Omega}^{P})\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}}$$\scriptstyle{r_{\lambda}}$$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{V}_{\lambda}^{\vee}(\overline{\mathbf{Q}}_{p}))\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\mathcal{E}_{\lambda,P,\chi}^{j_{\lambda},\eta_{0}}}$$\textstyle{\mathcal{O}_{\Omega}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\hskip
2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})}$$\textstyle{\overline{\mathbf{Q}}_{p}.}$ (10.4)

##### 10.1.1. Recap of classical evaluation maps

Let $\iota:H\to G$ be the map
$(h_{1},h_{2})\mapsto\left(\begin{smallmatrix}h_{1}&\\\
&h_{2}\end{smallmatrix}\right)$. The classical evaluation maps
$\mathcal{E}_{\lambda,P,\chi}^{j,\eta_{0}}$ were constructed as the
composition of:

######  Construction 10.3.

  1. (1)

Pull back classes twisted by $t_{P}^{\beta}$ under the map $\iota:H\to G$,

  2. (2)

Trivialise $\iota^{*}\mathscr{V}_{\lambda}^{\vee}$ on each connected component
and integrate over fundamental classes,

  3. (3)

Pass to scalars via a branching law for the critical integer $j$,

  4. (4)

Take the sum over connected components, weighted by $\chi$ and $\eta_{0}$.

When $P=Q$ (resp. $P=B$), the construction of (10.4) was done in [BDW, §5-6]
(resp. [BDG+, §11-12]). In that construction, we replaced the coefficients
$\mathscr{V}_{\lambda}^{\vee}$ in Construction 10.3 with
$\mathscr{D}_{\Omega}$. Of the four steps, the compatability of steps (1) and
(2) for $\mathscr{D}_{\Omega}$ and $\mathscr{V}_{\lambda}^{\vee}$ is easy via
[BDG+, Lemma 4.8], particularly Lemma 4.8. Step (4) is the same in both cases.
This leaves (3), which we handle by an interpolation of branching laws.

##### 10.1.2. Explicit branching laws

For integers $j_{1},j_{2}$, let $V_{(j_{1},j_{2})}^{H}$ denote the
1-dimensional $H(\mathbf{Z}_{p})$-representation given by the character
$\det_{1}^{j_{1}}\cdot\det_{2}^{j_{2}}$. Then we have [GR14, Prop. 6.3.1],
[BDW, Lem. 5.2]

$j\in\mathrm{Crit}(\lambda)\ \ \iff\ \ \mathrm{dim}\
\mathrm{Hom}_{H(\mathbf{Z}_{p})}\big{(}V_{\lambda}^{\vee},V^{H}_{(j,-{\sf
w}(\lambda)-j)}\big{)}=1.$

Via step (3) of Construction 10.3, the map
$\mathcal{E}_{\lambda,P,\chi}^{j,\eta_{0}}$ depends on a choice of generator
$\kappa_{\lambda,j}$ in this space, or dually, an element $v_{\lambda,j}\in
V_{(-j,{\sf w}(\lambda)+j)}^{H}\subset V_{\lambda}|_{H(\mathbf{Z}_{p})}$. For
$p$-adic interpolation, we need to choose such generators compatibly in
$\lambda$. It is expedient to recall how we handled the Borel case in [BDG+,
§11.1]; there we described explicit choices as follows. Define weights

$\displaystyle\alpha_{1}=(1,0,...,0,-1),\ \ \alpha_{2}=(1,1,0,...,0,-1,-1)$
$\displaystyle,\ \ ...,\ \ \alpha_{n-1}=(1,...,1,0,0,-1,...,-1),$
$\displaystyle\alpha_{0}=(1,...,1,1,...,1),\hskip 12.0pt$
$\displaystyle\alpha_{n}=(1,...,1,0,...,0),$ (10.5)

a $\mathbf{Z}$-basis for the pure algebraic weights. Note that if $\lambda$ is
a dominant algebraic weight then we can write uniquely

$\lambda=\lambda_{\pi}+\sum_{i=0}^{n}\mu_{i}\alpha_{i},\qquad\mu_{i}\in\mathbf{Z}_{\geqslant
0},$

so that ${\sf w}(\lambda)={\sf w}(\lambda_{\pi})+2\mu_{0}$. Note also that
$j\in\mathrm{Crit}(\lambda_{\pi})$ implies $j-\mu_{0}=j-{\sf
w}(\lambda-\lambda_{\pi})/2\in\mathrm{Crit}(\lambda)$, yielding the condition
in Proposition 10.2.

Via Notation 11.2 _op. cit._ , for $1\leqslant i\leqslant n-1$ let $v_{(i)}\in
V_{\alpha_{i}}(\mathbf{Q}_{p})$ such that $H(\mathbf{Z}_{p})$ acts trivially,
let $v_{(n),j}\in V_{\alpha_{n}}(\mathbf{Q}_{p})$ be such that
$H(\mathbf{Z}_{p})$ acts as $\det_{j}$ (for $j=1,2$), and fix a generator
$v_{(0)}\in V_{\alpha_{0}}(\mathbf{Q}_{p})$. In Proposition 11.3 _op. cit_. we
showed

$v_{\lambda,j}\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=[v_{(1)}^{\lambda_{1}-\lambda_{2}}]\cdot[v_{(2)}^{\lambda_{2}-\lambda_{3}}]\cdots[v_{(n-1)}^{\lambda_{n-1}-\lambda_{n}}]\cdot[v_{(n),1}^{-\lambda_{n+1}-j}]\cdot[v_{(n),2}^{\lambda_{n}+j}]\cdot[v_{(0)}^{\lambda_{n+1}}]$
(10.6)

generates $V_{(-j,{\sf w}(\lambda)+j)}^{H}(\mathbf{Q}_{p})\subset
V_{\lambda}(\mathbf{Q}_{p})|_{H(\mathbf{Z}_{p})}$. Dualising, we obtain a map
$\kappa_{\lambda,j}:V_{\lambda}^{\vee}\to V_{j,-{\sf w}(\lambda)-j}^{H}$ that
was used in the construction of $\mathcal{E}_{\lambda,B,\chi}^{j,\eta_{0}}$
(see [BDG+, Rem. 4.14]).

##### 10.1.3. $p$-adic interpolation

We recap the main points of [BDG+, §11], and simplify them; in that paper, we
also incorporated cyclotomic variation, but we shall not need this generality.

For $p$-adic variation of (10.6) we want to replace the algebraic weight
$\lambda$ with a more general character $\kappa$ of $T(\mathbf{Z}_{p})$. In
particular, we wish to make sense of $(\kappa_{i}-\kappa_{i+1})(v_{(i)})$. In
Proposition 11.4 _op. cit_. we showed that if we define

$N^{\beta}(\mathbf{Z}_{p})\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=N(p^{\beta}\mathbf{Z}_{p})\cdot
u=\left\\{n\in
N(\mathbf{Z}_{p}):n\equiv\left(\begin{smallmatrix}1_{n}&w_{n}\\\
0&1_{n}\end{smallmatrix}\right)\hskip 2.0pt(\mathrm{mod}\hskip
2.0ptp^{\beta})\right\\},$

then

$v_{(i)}[N^{\beta}(\mathbf{Z}_{p})]\subset 1+p^{\beta}\mathbf{Z}_{p},$ (10.7)

and hence
$(\kappa_{i}-\kappa_{i+1})(v_{(i)}\big{|}_{N^{\beta}(\mathbf{Z}_{p})})$ is
well-defined. This, and (10.6), motivates the definition

$\displaystyle w_{\kappa,\lambda_{\pi}}:N^{\beta}(\mathbf{Z}_{p})$
$\displaystyle\longrightarrow R^{\times},$ (10.8) $\displaystyle g$
$\displaystyle\longmapsto
v_{(0)}(g)^{\kappa_{n+1}}\cdot\left[\prod_{i=1}^{n-1}v_{(i)}(g)^{\kappa_{i}-\kappa_{i+1}}\right]\cdot
v_{(n),1}(g)^{-\lambda_{\pi,n+1}}\cdot v_{(n),2}(g)^{\lambda_{\pi,n}}.$

(In [BDG+], the last two terms used $\kappa_{i}$ rather than
$\lambda_{\pi,i}$, because we also wanted cyclotomic variation. Here we fix
these terms, which allows us to fix $j$ and still obtain interpolation of
$v_{\lambda,j_{\lambda}}$ as $\lambda$ varies; see (10.9) below).

Now let $\Omega\subset\mathscr{W}_{0}^{G}$, with universal character
$\kappa_{\Omega}$ on $T(\mathbf{Z}_{p})$. For
$j\in\mathrm{Crit}(\lambda_{\pi})$, define a function
$v_{\Omega,j}:N(\mathbf{Z}_{p})\to\mathcal{O}_{\Omega}$ by

$v_{\Omega,j}(g)\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\left\\{\begin{array}[]{cc}w_{\kappa_{\Omega},\lambda_{\pi}}(g)\cdot\left(\tfrac{v_{(n),2}(g)}{v_{(n),1}(g)}\right)^{j}&:g\in
N^{\beta}(\mathbf{Z}_{p}),\\\ 0&:\text{otherwise}.\end{array}\right.$

Now suppose $\lambda$ is a classical weight, with ${\sf w}(\lambda)={\sf
w}(\lambda_{\pi})+2\mu_{0}$. Recall
$j_{\lambda}=j-\mu_{0}\in\mathrm{Crit}(\lambda)$. We know
$\kappa_{\Omega}\hskip 2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})=\lambda$ as characters of $T(\mathbf{Z}_{p})$,
and one may formally verify that

$v_{\Omega,j}\hskip 2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})=v_{\lambda,j_{\lambda}}|_{N^{\beta}(\mathbf{Z}_{p})}.$
(10.9)

The function $v_{\Omega,j}$ extends to a unique element of
$\mathcal{A}_{\Omega}$, and dualising, we get a ‘$p$-adic branching law’
$\kappa_{\Omega,j}:\mathcal{D}_{\Omega}\to\overline{\mathbf{Q}}_{p}$ that,
after restriction to $N^{\beta}(\mathbf{Z}_{p})$, formally interpolates the
branching laws $\kappa_{\lambda,j}$ as $\lambda$ varies in $\Omega$.

In the construction of $\mathcal{E}_{\Omega,B,\chi}^{j,\eta_{0}}$, by [BDG+,
Lem. 12.4] the result of steps (1) and (2) (in Construction 10.3, with
$\mathscr{D}_{\Omega}$ coefficients) was a distribution supported on
$t_{B}^{\beta}N(\mathbf{Z}_{p})t_{B}^{-\beta}u\subset
N^{\beta}(\mathbf{Z}_{p})$; so we could use $\kappa_{\Omega,j}$ to construct
$\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}$ (in Proposition 12.3).

We switch to a general parabolic $P$. Let
$\mathcal{D}_{\Omega}^{\beta,P}\subset\mathcal{D}_{\Omega}^{P}$ be the subset
of distributions supported on
$N_{P}^{\beta}(\mathbf{Z}_{p})\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=t_{P}^{\beta}N_{P}(\mathbf{Z}_{p})t_{P}^{-\beta}u$
(analogous to [BDG+, Def. 11.11]). For a general parabolic $P$, by the same
proof as [BDG+, Lem. 12.4], the output of steps (1) and (2) of Construction
10.3 lies in (a quotient of) $\mathcal{D}_{\Omega}^{\beta,P}$. Since
$N_{P}^{\beta}(\mathbf{Z}_{p})\subset N^{\beta}(\mathbf{Z}_{p})$, we can
define $v_{\Omega,j}^{P}:N_{P}(\mathbf{Z}_{p})\to\overline{\mathbf{Q}}_{p}$ by

$v_{\Omega,j}^{P}(g)\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\left\\{\begin{array}[]{cc}v_{\Omega,j}(g)&:g\in
N_{P}^{\beta}(\mathbf{Z}_{p}),\\\ 0&:\text{otherwise}.\end{array}\right.$

The function $v_{\Omega,j}^{P}$ extends uniquely via the induction property
[BDW, Def. 3.11] to an element in $\mathcal{A}_{\Omega}^{P}$, and hence
dualises to a map

$\kappa_{\Omega,j}^{P}:\mathcal{D}_{\Omega}^{\beta,P}\longrightarrow\mathcal{O}_{\Omega},\qquad\mu\mapsto\mu(v_{\Omega,j}^{P}).$

Again, formally, $\kappa_{\Omega,j}^{P}$ interpolates the branching laws
$\kappa_{\lambda,j_{\lambda}}$ after restriction to
$N_{P}^{\beta}(\mathbf{Z}_{p})$.

_Proof of Proposition 10.2_: As in [BDG+, Rems. 4.14, 12.7], define
$\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}$ as the composition

$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{D}_{\Omega}^{P})\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\oplus\mathrm{Ev}_{P,\beta,\delta}^{\mathcal{D}_{\Omega}^{P}}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}(\mathcal{D}_{\Omega}^{\beta,P})_{\Gamma_{\beta,\delta}^{P}}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\delta*\kappa_{\Omega,j}^{P}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}\mathcal{O}_{\Omega}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\sum_{d}\chi(d)\Xi_{d}^{\eta_{0}}}$$\textstyle{\mathcal{O}_{\Omega},}$
(10.10)

with $\mathrm{Ev}_{P,\beta,\delta}^{\mathcal{D}_{\Omega}^{P}}$ the map of
Definition 4.7 _op. cit._ , which lands in
$(\mathcal{D}_{\Omega}^{\beta,P})_{\Gamma_{\beta,\delta}^{P}}$ exactly as in
Lemma 12.4; $\kappa_{\Omega,j}^{P}$ descends to the coinvariants as in the
proof of Proposition 12.3; and $\Xi_{d^{\eta_{0}}}$ is defined in Remark 4.14,
all _op. cit_., where any other undefined notation is explained. The three
arrows in (10.10) correspond to (1-2), (3) and (4) in Construction 10.3
respectively.

To deduce the claimed interpolation property in Proposition 10.2, observe that
for any classical $\lambda\in\Omega,$ the diagram

$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{D}_{\Omega}^{P})\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\oplus\mathrm{Ev}_{P,\beta,\delta}^{\mathcal{D}_{\Omega}}}$$\scriptstyle{r_{\lambda}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}(\mathcal{D}_{\Omega}^{\beta,P})_{\Gamma_{\beta,\delta}^{P}}\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\delta*\kappa_{\Omega,j}}$$\scriptstyle{r_{\lambda}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}\mathcal{O}_{\Omega}\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\sum_{d}\chi(d)\Xi_{d}^{\eta_{0}}}$$\scriptstyle{\hskip
2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})}$$\textstyle{\mathcal{O}_{\Omega}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\hskip
2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})}$$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K},\mathscr{V}_{\lambda}^{\vee})\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\oplus\mathrm{Ev}_{P,\beta,\delta}^{V_{\lambda}^{\vee}}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}(V_{\lambda}^{\vee})_{\Gamma_{\beta,\delta}^{P}}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\delta*\kappa_{\lambda,j_{\lambda}}}$$\textstyle{\displaystyle\bigoplus_{[\delta]}L\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\sum_{d}\chi(d)\Xi_{d}^{\eta_{0}}}$$\textstyle{L}$

commutes. For the first square, this is [BDG+, Lem. 4.8]; the second is
identical to Proposition 11.12 _op. cit_ ; and the third is clear from the
definition. Since the bottom row here is exactly
$\mathcal{E}_{\lambda,P,\chi}^{j_{\lambda},\eta_{0}}$, this concludes the
proof of Proposition 10.2 (hence of Theorem 8.6). ∎

#### 10.2. Tracing from Iwahoric to parahoric level

The above ‘big evaluation’ had the parabolic $P$ baked into it; it used the
parahoric classical evaluation map, and $P$-parahoric distributions in the
overconvergent cohomology. As in [BDW], this is sufficient to study symplectic
families through $\tilde{\pi}^{P}$ in the _$P$ -parabolic eigenvariety_, where
we have analytic variation of some subset of the Hecke operators $U_{p,r}$.
However, our study of the symplectic locus crucially used analytic variation
of _all_ the $U_{p,r}$; in other words, it applies only to the Iwahori-level
eigenvariety. We now port between the two.

There is a natural trace map
$\mathrm{Tr}:\pi_{p}^{\mathrm{Iw}_{G}}\to\pi_{p}^{J_{P}}$, given by summing
over translates by representatives of $J_{P}/\mathrm{Iw}$.

######  Lemma 10.4.

If $\tilde{\pi}=(\pi,\alpha)$ is an Iwahori refinement above the
$P$-refinement $\tilde{\pi}^{P}=(\pi,\alpha^{P})$, then $\mathrm{Tr}$ induces
an isomorphism
$\tilde{\pi}\xrightarrow{\,\smash{\raisebox{-2.79857pt}{$\scriptstyle\sim$}}\,}\tilde{\pi}^{P}$.

###### Proof.

As trace only acts at $p$, it suffices to prove
$\mathrm{Tr}:\tilde{\pi}_{p}\xrightarrow{\,\smash{\raisebox{-2.79857pt}{$\scriptstyle\sim$}}\,}\tilde{\pi}_{p}^{P}$.
As the Satake parameter of $\pi_{p}$ is assumed regular, both sides are
complex lines; so we need only check the map is well-defined and non-zero.

Let $\sigma=\Psi_{\theta}(\tilde{\pi})$. We have
$\pi_{p}\cong\operatorname{Ind}_{B}^{G}(\theta^{\sigma})$, so it suffices to
prove the result in $\operatorname{Ind}_{B}^{G}\theta^{\sigma}$. Let
$f_{\sigma}\in\operatorname{Ind}_{B}^{G}\theta^{\sigma}$ be the (unique)
Iwahori-invariant function supported on the big Bruhat cell
$B(\mathbf{Q}_{p})\cdot w_{2n}\cdot\mathrm{Iw}_{G}$ with
$f_{\sigma}(w_{2n})=1$. By [BDG+, Prop. 7.4], $f_{\sigma}$ is an
$\alpha$-eigenvector, hence yields a generator of $\tilde{\pi}_{p}$. Under
trace, this is mapped to a non-zero $J_{P}$-invariant vector supported on
$B(\mathbf{Q}_{p})\cdot w_{2n}\cdot J_{P}$. But by the same arguments, this is
an $\alpha^{P}$-eigenvector, hence the map on refinements is well-defined and
non-zero. ∎

Let $K_{B}=K^{p}\mathrm{Iw}_{G}$ be an Iwahori-at-$p$ level, and
$K_{P}=K^{p}J_{P}$ a parahoric-at-$p$ level. We have natural trace maps from
the cohomology of $S_{K_{B}}$ to $S_{K_{P}}$, which are functorial in maps
between the coefficients. Finally, we have a natural map
$s_{P}:\mathcal{D}_{\Omega}\twoheadrightarrow\mathcal{D}_{\Omega}^{P}$ [BW21,
Prop. 4.8], and $r_{\lambda}:\mathcal{D}_{\Omega}\to V_{\lambda}^{\vee}$
factors through $s_{P}$. Putting this all together with Proposition 10.2 and
Lemma 10.4 yields:

######  Lemma 10.5.

For any classical $\lambda\in\Omega$, here is a commutative diagram

$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{r_{\lambda}}$$\scriptstyle{\mathrm{Tr}\circ
s_{P}}$$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{P}},\mathscr{D}_{\Omega}^{P})\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{r_{\lambda}}$$\scriptstyle{\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}}$$\textstyle{\mathcal{O}_{\Omega}\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\hskip
2.0pt(\mathrm{mod}\hskip
2.0pt\mathfrak{m}_{\lambda})}$$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{V}_{\lambda}^{\vee})\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\mathrm{Tr}}$$\textstyle{\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{P}},\mathscr{V}_{\lambda}^{\vee})\ignorespaces\ignorespaces\ignorespaces\ignorespaces}$$\scriptstyle{\mathcal{E}_{\lambda,P,\chi}^{j,\eta_{0}}}$$\textstyle{L.}$
(10.11)

#### 10.3. Symplectic families in the parabolic eigenvariety

Now suppose $(1^{\prime})$ of Conjecture 8.10 holds, giving
$\varphi_{p}\in\tilde{\pi}^{P}$ with
$\zeta_{p}(ut_{P}^{\beta}\cdot\varphi_{p},\chi_{p},s+1/2)\neq 0$ (for all $s$,
by Corollary 9.2). Let $\tilde{\pi}$ be as given by the hypotheses of Theorem
8.6. Let $\varphi_{p}^{\prime}\in\tilde{\pi}_{p}$ be a lift of $\varphi_{p}$
under the trace map (via Lemma 10.4). Let $\varphi=\otimes_{\ell\neq
p}\varphi_{\ell}^{\mathrm{FJ}}\otimes\varphi_{p}^{\prime}\in\tilde{\pi}$. By
(10.1), attached to this is a cohomology class
$\phi_{\varphi}\in\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{V}_{\lambda_{\pi}}^{\vee})_{\tilde{\pi}}$.
By (10.3), we have

$\mathcal{E}_{\lambda_{\pi},P,\chi}^{j,\eta_{0}}\circ\mathrm{Tr}(\phi_{\varphi})=A_{\lambda_{\pi},P,\chi}^{j}\cdot
L\Big{(}\pi\times\chi,j+\tfrac{1}{2}\Big{)}\cdot\zeta_{p}\Big{(}ut_{P}^{\beta}\cdot\varphi_{p},\chi_{p},j+\tfrac{1}{2}\Big{)}\neq
0,$ (10.12)

where non-vanishing is by assumption $(1^{\prime})$.

By hypothesis, the map
$r_{\tilde{\pi}}:\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})\to\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{V}_{\lambda_{\pi}}^{\vee})_{\tilde{\pi}}$
is surjective for some neighbourhood
$\Omega\subset\mathscr{W}_{0,\lambda_{\pi}}^{P}$ of $\lambda_{\pi}$. We
summarise some consequences, described in detail in [BDW, §7.2,7.3]:

  * •

By Hecke-equivariance of $r_{\lambda_{\pi}}$, for $h\gg 0$ the localisation of
the slope $\leqslant h$ subspace
$\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})^{\leqslant h}$ at
$\tilde{\pi}$ is non-zero, giving a point $x_{\tilde{\pi}}$ in the top-degree
eigenvariety. Let $\mathscr{C}^{\prime}$ be the connected component through
$x_{\tilde{\pi}}$.

  * •

Let $\Phi$ be a lift of $\phi_{\varphi}$, and $\Phi_{\mathscr{C}^{\prime}}$ be
its projection to the direct summand of
$\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})^{\leqslant h}$
corresponding to $\mathscr{C}^{\prime}$. Then
$\Phi_{\mathscr{C}^{\prime}}\in\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})$
with $r_{\tilde{\pi}}(\Phi_{\mathscr{C}^{\prime}})=\phi_{\varphi}$.

  * •

Let
$\mathcal{E}_{\Omega}\mathrel{\vbox{\hbox{\scriptsize.}\hbox{\scriptsize.}}}=\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}\circ\mathrm{Tr}\circ
s_{P}:\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{D}_{\Omega})\to\mathcal{O}_{\Omega}$,
an $\mathcal{O}_{\Omega}$-module map. By (10.12) and Lemma 10.5, we have
$\mathcal{E}_{\Omega}(\Phi_{\mathscr{C}^{\prime}})\neq 0\hskip
2.0pt(\mathrm{mod}\hskip 2.0pt\mathfrak{m}_{\lambda_{\pi}})$, so
$\mathcal{E}_{\Omega}(\Phi_{\mathscr{C}^{\prime}})\neq 0$. As
$\mathcal{O}_{\Omega}$ is torsion-free, we deduce that
$\mathrm{Ann}_{\mathcal{O}_{\Omega}}(\Phi_{\mathscr{C}^{\prime}})=0$. As in
[BDW, Cor. 7.12] this forces existence of an irreducible component
$\mathscr{C}\subset\mathscr{C}^{\prime}$ of dimension $\mathrm{dim}(\Omega)$.

######  Lemma 10.6.

We may take $\mathscr{C}$ to be a classical family.

###### Proof.

Up to replacing $\Omega$ with an open neighbourhood of $\lambda_{\pi}$ of the
same dimension, we may assume the rigid-analytic function
$\mathcal{E}_{\Omega}(\Phi_{\mathscr{C}^{\prime}})\in\mathcal{O}_{\Omega}$ is
non-vanishing on $\Omega$. At any classical weight $\lambda\in\Omega$,
combining non-vanishing of
$\mathcal{E}_{\Omega}(\Phi_{\mathscr{C}^{\prime}})\hskip
2.0pt(\mathrm{mod}\hskip 2.0pt\mathfrak{m}_{\lambda})$ with Lemma 10.5 implies
$\Phi_{\mathscr{C}^{\prime}}$ has non-zero image in
$\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{V}_{\lambda}^{\vee})$. It must
therefore have non-zero image after projection to at least one of the finite
number of Hecke eigensystems that appear in
$\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{B}},\mathscr{V}_{\lambda}^{\vee})$, so
there is a classical point of $\mathscr{C}^{\prime}$ of weight $\lambda$. The
result follows from Zariski-density of such $\lambda$ in $\Omega$, and the
fact $\mathscr{C}^{\prime}$ has finitely many irreducible components. ∎

######  Lemma 10.7.

If $\mathscr{C}$ as above is a classical family, it is a cuspidal symplectic
family.

###### Proof.

We first exhibit a related family in the _parabolic_ eigenvariety. At
parahoric level,
$r_{\tilde{\pi}}:\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{P}},\mathscr{D}_{\Omega}^{P})\to\mathrm{H}^{t}_{\mathrm{c}}(S_{K_{P}},\mathscr{V}_{\lambda_{\pi}}^{\vee})_{\tilde{\pi}}$
is surjective by Lemma 10.5, as the left-hand map surjects onto the
$\tilde{\pi}$-eigenspace (by assumption) and the bottom map is an isomorphism
on the $\tilde{\pi}$-eigenspaces (by Lemma 10.4). In particular, we can apply
all of the above arguments (with $\mathcal{E}_{\Omega,P,\chi}^{j,\eta_{0}}$
replacing $\mathcal{E}_{\Omega}$) to exhibit a classical family
$\mathscr{C}^{P}$ in the $P$-parabolic eigenvariety. This family also varies
over $\Omega$ and by Lemma 10.5, there is a bijection between classical points
of $\mathscr{C}$ and $\mathscr{C}^{P}$, where every classical point $y$ of
$\mathscr{C}$ is a further Iwahori-refinement of a $P$-refined
$\tilde{\pi}_{y}^{P}$ appearing in $\mathscr{C}$. To show $\mathscr{C}$ is
cuspidal, then, it suffices to prove $\mathscr{C}^{P}$ is a cuspidal family.

By assumption, $\tilde{\pi}^{P}$ is $P$-strongly-interior and has regular
weight. As in [BW21, Prop. 5.15], a Zariski-dense set of classical points in
$\mathscr{C}^{P}$ are also $P$-strongly-interior, have regular weight, and are
non-$P$-critical slope. As _op. cit_., this forces them to be cuspidal.

Finally, a Zariski-density of symplectic points follows exactly as in [BDW,
§7.4]. ∎

This $\mathscr{C}$ is the family required in Proposition 10.1, completing the
proof of Theorem 8.6. ∎

### References

  * [AG94] Avner Ash and David Ginzburg.  $p$-adic $L$-functions for ${\rm GL}(2n)$.  Invent. Math., 116(1-3):27–73, 1994.
  * [APS08] Avner Ash, David Pollack, and Glenn Stevens.  Rigidity of $p$-adic cohomology classes of congruence subgroups of ${\rm GL}(n,\mathbb{Z})$.  Proc. Lond. Math. Soc. (3), 96(2):367–388, 2008.
  * [AS06] Mahdi Asgari and Freydoon Shahidi.  Generic transfer for general spin groups.  Duke Math. J., 132(1):137–190, 2006.
  * [AS14] Mahdi Asgari and Freydoon Shahidi.  Image of functoriality for general spin groups.  Manuscripta Math., 144(3-4):609–638, 2014.
  * [Asg02] Mahdi Asgari.  Local $L$-functions for split spinor groups.  Canad. J. Math., 54(4):673–693, 2002.
  * [BDG+] Daniel Barrera Salazar, Mladen Dimitrov, Andrew Graham, Andrei Jorza, and Chris Williams.  On the GL(2n) eigenvariety: branching laws, Shalika families and $p$-adic ${L}$-functions.  Preprint: https://arxiv.org/abs/2211.08126.
  * [BDW] Daniel Barrera Salazar, Mladen Dimitrov, and Chris Williams.  On $p$-adic $L$-functions for $\mathrm{{GL}}(2n)$ in finite slope Shalika families.  Preprint: https://arxiv.org/abs/2103.10907.
  * [BW21] Daniel Barrera Salazar and Chris Williams.  Parabolic eigenvarieties via overconvergent cohomology.  Math. Z., 299(1-2):961–995, 2021.
  * [BZ77] I. N. Bernstein and A. V. Zelevinsky.  Induced representations of reductive ${p}$-adic groups. I.  Ann. Sci. École Norm. Sup. (4), 10(4):441–472, 1977.
  * [Cas80] W. Casselman.  The unramified principal series of $\mathfrak{p}$-adic groups. I. The spherical function.  Compositio Math., 40(3):387–406, 1980.
  * [Che04] Gaëtan Chenevier.  Familles $p$-adiques de formes automorphes pour ${\rm GL}_{n}$.  J. Reine Angew. Math., 570:143–217, 2004.
  * [Che05] Gaëtan Chenevier.  Une correspondance de Jacquet-Langlands $p$-adique.  Duke Math. J., 126(1):161–194, 2005.
  * [Clo90] Laurent Clozel.  Motifs et formes automorphes: applications du principe de fonctorialité.  In Automorphic forms, Shimura varieties, and $L$-functions, Vol. I (Ann Arbor, MI, 1988), volume 10 of Perspect. Math., pages 77–159. Academic Press, Boston, MA, 1990.
  * [CM09] Frank Calegari and Barry Mazur.  Nearly ordinary Galois deformations over arbitrary number fields.  J. Inst. Math. Jussieu, 8(1):99–177, 2009.
  * [DJR20] Mladen Dimitrov, Fabian Januszewski, and A. Raghuram.  ${L}$-functions of $\mathrm{GL}(2n)$: $p$-adic properties and nonvanishing of twists.  Compositio Math., 156(12):2437–2468, 2020.
  * [FJ93] Solomon Friedberg and Hervé Jacquet.  Linear periods.  J. Reine Angew. Math., 443:91–139, 1993.
  * [GM98] Fernando Q. Gouvêa and Barry Mazur.  On the density of modular representations.  In Computational perspectives on number theory (Chicago, IL, 1995), volume 7 of AMS/IP Stud. Adv. Math., pages 127–142. Amer. Math. Soc., Providence, RI, 1998.
  * [GR14] Harald Grobner and A. Raghuram.  On the arithmetic of Shalika models and the critical values of $L$-functions for ${\rm GL}_{2n}$.  Amer. J. Math., 136(3):675–728, 2014.  With an appendix by Wee Teck Gan.
  * [Han17] David Hansen.  Universal eigenvarieties, trianguline Galois representations and $p$-adic Langlands functoriality.  J. Reine. Angew. Math., 730:1–64, 2017.
  * [HS] Valentin Hernandez and Benjamin Schraen.  The infinite fern in higher dimensions.  Preprint: https://arxiv.org/abs/2210.10564.
  * [HL11] Richard Hill and David Loeffler.  Emerton’s Jacquet functors for non-Borel parabolic subgroups.  Doc. Math., 16:1–31, 2011.
  * [HS16] Joseph Hundley and Eitan Sayag.  Descent construction for GSpin groups.  Mem. Amer. Math. Soc., 243(1148):v+124, 2016.
  * [Hum90] James E. Humphreys.  Reflection groups and Coxeter groups, volume 29 of Cambridge Studies in Advanced Mathematics.  Cambridge University Press, Cambridge, 1990.
  * [JLR99] Hervé Jacquet, Erez Lapid, and Jonathan Rogawski.  Periods of automorphic forms.  J. Amer. Math. Soc., 12(1):173–240, 1999.
  * [JN19] Christian Johansson and James Newton.  Irreducible components of extended eigenvarieties and interpolating Langlands functoriality.  Math. Res. Lett., 26(1):159–201, 2019.
  * [JPSS81] Hervé Jacquet, Ilja Piatetski-Shapiro, and Joseph Shalika.  Conducteur des représentations génériques du groupe linéaire.  C. R. Acad. Sci. Paris Sér. I Math., 292(13):611–616, 1981\.
  * [OST] Masao Oi, Ryotaro Sakamoto, and Hiroyoshi Tamori.  New expression of unramified local ${L}$-functions by certain Hecke operators.  Preprint: https://arxiv.org/abs/1903.07613.
  * [Pan94] Alexei A. Panchishkin.  Motives over totally real fields and $p$-adic $L$-functions.  Ann. Inst. Fourier (Grenoble), 44(4):989–1023, 1994.
  * [Roc] Rob Rockwood.  Plus/minus $p$-adic $L$-functions for GL2n.  Ann. Math. Quebec.  To appear.
  * [Sun19] Binyong Sun.  Cohomologically induced distinguished representations and cohomological test vectors.  Duke Math. J., 168(1):85–126, 2019.
  * [SV17] Yiannis Sakellaridis and Akshay Venkatesh.  Periods and harmonic analysis on spherical varieties.  Astérisque, (396):viii+360, 2017.
  * [Urb11] Eric Urban.  Eigenvarieties for reductive groups.  Ann. of Math. (2), 174(3):1685–1784, 2011.
  * [Wil] Chris Williams.  On $p$-adic $L$-functions for symplectic representations of $\mathrm{GL}_{N}$ over number fields.  Preprint.
  * [Xia18] Zhengyu Xiang.  Twisted eigenvarieties and self-dual representations.  Ann. Inst. Fourier (Grenoble), 68(6):2381–2444, 2018.


# Typed Design Patterns for the Functional Era

Will Crichton<EMAIL_ADDRESS>0000-0001-8639-6541 Brown
UniversityProvidenceRhode Island02912USA

(2023; 2023-06-01; 2023-06-28)

###### Abstract.

This paper explores how design patterns could be revisited in the era of
mainstream functional programming languages. I discuss the kinds of knowledge
that ought to be represented as functional design patterns: architectural
concepts that are relatively self-contained, but whose entirety cannot be
represented as a language-level abstraction. I present four concrete examples
embodying this idea: the Witness, the State Machine, the Parallel Lists, and
the Registry. Each pattern is implemented in Rust to demonstrate how careful
use of a sophisticated type system can better model each domain construct and
thereby catch user mistakes at compile-time.

design patterns, domain-driven design, rust

††copyright: acmlicensed††price: 15.00††doi:
10.1145/3609025.3609477††journalyear: 2023††submissionid: icfpws23funarchmain-
id3-p††isbn: 979-8-4007-0297-6/23/09††conference: Proceedings of the 1st ACM
SIGPLAN International Workshop on Functional Software Architecture; September
8, 2023; Seattle, WA, USA††booktitle: Proceedings of the 1st ACM SIGPLAN
International Workshop on Functional Software Architecture (FUNARCH ’23),
September 8, 2023, Seattle, WA, USA††ccs: Software and its engineering Design
patterns††ccs: Software and its engineering Functional languages

##  1\. Introduction

_Where are all the functional programming design patterns?_ People have been
clamoring for answers to this question for over a decade (2011). As functional
programming concepts have crept into the mainstream of software engineering,
that clamor has only grown. Yet, no catalog has emerged as the clear
functional successor to the venerable Design Patterns (Gamma et al., 1994).
This paper explores the question: what might a catalog of functional design
patterns look like?

First, it is worth discussing the definition and purpose of a software design
pattern. Norvig (1998) argued that a design pattern should provide
“descriptions of what experienced designers know (that isn’t written down in
the Language Manual)”. The Gang of Four (GoF) further explain:

> “Each design pattern systematically names, explains, and evaluates an
> important and recurring design in object-oriented systems. Our goal is to
> capture design experience in a form that people can use effectively. To this
> end we have documented some of the most important design patterns and
> present them as a catalog.” (Gamma et al., 1994, p. 4)

Put another way, a design pattern satisfies two key criteria:

  1. (1)

It captures a recurring phenomenon (a pattern) in real-world system design.

  2. (2)

It provides a software design strategy for managing this phenomenon that is
difficult to describe mechanistically.

The first criterion points to why functional design patterns are still
uncommon. There are not nearly as many large-scale systems written with
functional languages compared to OOP languages. But this is slowly changing —
the last decade has seen an explosion of systems implemented in functional
languages111This list may raise some eyebrows as to my definition of
“functional”. I mean languages with features associated with the intellectual
lineage of the lambda calculus. like Rust, Scala, Swift, and Clojure. I
personally have close to a decade of experience with Rust, which underlies the
perspective given in this paper. After working with Rust systems for web
development, 3D graphics, data analytics, etc., I have seen many patterns of
system design with various encodings into Rust. But I have never seen these
patterns articulated concisely and collated into a single catalog.

The second criterion points to why the idea of design patterns has been tricky
to translate into a functional setting. A common critique of the GoF patterns
is that their complexity stems from an impoverished implementation language
like C++. Norvig (1998) showed that use of a dynamically-typed language like
Lisp or Dylan can dramatically simplify some patterns to the point of
triviality. Gibbons (2006) showed that the use of a Haskell-esque type system
enables patterns to be directly represented as well-typed library-level
abstractions. From this perspective, one could argue that the Haskell or Rust
standard libraries are design pattern catalogues per se, just communicated via
code rather than prose.

However, it is undoubtedly true that an FP novice cannot simply read the
Haskell or Rust language manuals and proceed to effectively design a complex
system. A key skill that bridges the gap is understanding how to
_systematically map domain concepts to language features_. With object-
oriented programming, developers have the problem of modeling a diverse range
of domain concepts with a small set of load-bearing features. By contrast,
functional languages offer a dizzying array of modeling tools: products, sums,
newtypes, generics, modules, traits, type families, substructural types,
lifetimes, and so on. FP novices therefore have a different problem: deciding
which combination of many features is most appropriate for modeling a domain
concept.

This paper articulates a vision for (typed) functional design patterns to
match this new reality. I propose that functional design patterns should
articulate concrete mappings from common domain concepts to particular
configurations of functional language features. That vision is presented
through four concrete patterns: the Witness, the State Machine, the Parallel
Lists, and the Registry. The selection, structure, and substance of each
pattern embodies my argument for what constitutes a useful software design
pattern.

##  2\. A Sample of Functional Design Patterns

Drawing inspiration from domain-driven design (Evans, 2003; Wlaschin, 2017),
each design pattern is centered around a “domain pattern”, i.e. a language-
independent concept that appears in many software application domains. A
domain pattern is described in terms of a “schema”, in the sense used in
psychological schema theory (Rumelhart, 1980). The knowledge captured in each
design pattern is about how to model the domain pattern at both the type-level
and expression-level of a particular functional programming language. The
quality of a model is evidenced by the fact that incorrect uses of the model
cause type errors rather than runtime errors (or worse, undefined behavior).
Each pattern is described using the following structure:

  1. (1)

Schema: the abstract elements (written in Small Caps) and relations that
characterize the domain pattern.

  2. (2)

Examples: a short list of instances of the pattern in real-world applications,
briefly fit to the schema.

  3. (3)

Case study: an extended case study of how to implement one instance of the
pattern.

  4. (4)

Commentary: some additional notes about the pattern.

The case studies are all implemented in Rust. That decision is in part due to
my familiarity with the language. But it bears emphasizing that Rust is an
excellent medium for articulating functional design patterns. Rust is an
exceptionally practical language, designed for implementing production-grade
systems rather than as a vehicle for research. Functional design patterns
should focus on mappings that are _practical_ as much as _feasible_ , and the
best way to determine practicality is under heavy stress from real-world use.

###  2.1. Witness

Schema: An Action that can only execute once a particular Condition is
satisfied.

Examples: Access control (e.g., a user must login before seeing their
profile), resource management (e.g., a computation can only occur if the
machine has enough resources).

Case study: Consider a website that has normal and admin users, and an admin
panel that should only be accessed (the Action) to users logged in as an admin
(the Condition). The base API contains the following methods:

  * •

`render_admin_panel() -> Html`: returns the HTML for the admin panel.

  * •

`render_404() -> Html`: returns the HTML for a 404 page.

  * •

`current_user() -> User`: returns the currently logged-in user.

  * •

`is_admin(&User) -> bool`: returns true if the user is an admin.

Figure 1 provides both a correct and incorrect (but well-typed) implementation
of a route for the admin panel. The correct admin panel route verifies that
the current user is an admin, and returns a 404 otherwise. The issue with this
implementation is that if we forget to check that the current user is an
admin, or e.g. mess up the check, then the program could permit non-admins to
see the admin panel.

⬇

#[route(”/admin”)]

fn admin_panel() -> Html {

if is_admin(&current_user()) {

render_admin_panel();

} else {

render_404();

}

}

\par#[route(”/admin”)]

fn admin_panel_bad() -> Html {

// Allowed to compile, leaks information

render_admin_panel()

}

Figure 1. Admin panel with a boolean encoding of the admin flag on users.

An alternative encoding is shown in Figure 2. The key idea is to create a new
data type that “witnesses” the proof of a capability, i.e. that a user is an
admin. The `Admin` data type is wrapped in a module so it can only be
constructed via the `try_admin` method. The `render_admin_panel` function is
modified such that it takes an `Admin` as input. Therefore the only well-typed
way to call the function is to generate a proof that the user (or at least a
user) is an admin, and pass that proof to the renderer.

⬇

mod admin {

pub struct Admin {}

impl User {

pub fn try_admin(&self) -> Option<Admin> {

if is_admin(self) { Some(Admin {}) }

else { None }

}

}

}

\parfn render_admin_panel(_admin: Admin) -> Html;

\par#[route(”/admin”)]

fn admin_panel() -> Html {

if let Some(admin) = current_user().try_admin() {

render_admin_panel(admin);

} else {

render_404();

}

}

\par#[route(”/admin”])

fn admin_panel_bad() -> Html {

// Doesn’t compile, missing witness

render_admin_panel()

// Doesn’t compile, can’t manually build witness

render_admin_panel(Admin {})

}

Figure 2. Admin panel with a witness encoding of the admin permission.

Commentary: While many type-driven design techniques are inspired by theorem
proving, the witness technique is most directly drawn from that intellectual
lineage. As applications become more security- and privacy-sensitive, design
patterns can help developers write correct-by-construction code with respect
to issues like access control. This pattern has been adopted in Rust web
applications, most notably Rocket ([1,3]https://rocket.rs////), as well as
some cryptography libraries.

###  2.2. State Machine

Schema: An object that exists in one of multiple States, which can Transition
to other States in response to Events.

Examples: Files (open and closed), mutexes (unlocked and locked), shopping
carts (empty, filled, purchased).

Case study: Consider a file model with three States: reading, end-of-file, and
closed. Figure 3 shows a diagram of the model.

ReadEofClose

`sys_close`

`sys_close`

`sys_read`

`sys_read`

`sys_open`

Figure 3. Model of the file state machine.

An operating system provides a low-level API (i.e. a set of Transitions) that
implements the model:

  * •

`sys_open(&str) -> Descriptor`: creates a file descriptor.

  * •

`sys_eof(&Descriptor) -> bool`: checks if the file has reached EOF, or panics
if the file is closed.

  * •

`sys_read(&mut Descriptor) -> Vec<u8>`: returns a data buffer from the file,
or panics if the file has reached EOF or closed.

  * •

`sys_close(&mut Descriptor)`: closes the file, or panics if the file is
already closed.

Consider the task of designing a `File` type that encapsulates the low-level
API. Figure 4 shows a trivial wrapper. This wrapper provides no protection
against incorrect usage. For example, one could attempt to read a file after
reaching EOF which would panic, such as in Figure 5.

⬇

struct File { fd: Descriptor }

impl File {

fn open(path: &str) -> File {

File { fd: sys_open(path) }

}

fn eof(&self) -> bool {

sys_eof(&self.fd)

}

fn read(&mut self) -> Vec<u8> {

sys_read(&mut self.fd)

}

fn close(&mut self) {

sys_close(&mut self.fd);

}

}

Figure 4. File state machine that directly wraps the system API.

⬇

fn main() {

let mut f = File::open(”f.txt”);

// permits reading past EOF

f.read(); f.read(); f.read();

// permits closing multiple times

f.close(); f.close();

// permits reading after close

f.read();

}

Figure 5. Example usage of the file state machine wrapper API.

One way to make the API less error-prone is to represent all states within one
enumerated type, and then change the methods to return option types that
indicate incorrect state transitions. Figure 6 shows an implementation of this
idea. The enum representation ensures that panics cannot happen within the
`File` implementation. However, a user may still encounter unexpected `None`
values at runtime from an incorrect usage of the API as shown in Figure 7.

⬇

enum State { Read, Eof, Close }

struct File { fd: Descriptor, state: State }

\parimpl File {

fn open(path: &str) -> File {

File { fd: sys_open(path), state: State::Read }

}

\parfn read(&mut self) -> Option<Vec<u8>> {

match self.state {

State::Read => {

let buf = sys_read(&mut self.fd);

if sys_eof(&self.fd) {

self.state = State::Eof;

}

Some(buf)

}

State::Eof | State::Close => None

}

}

\parfn close(&mut self) -> Option<()> {

match self.state {

State::Read | State::Eof => {

sys_close(&mut self.fd);

self.state = State::Close;

Some(())

}

State::Close => None

}

}

}

Figure 6. File state machine with enum encoding.

⬇

fn main() {

let mut f = File::open(”hello.txt”);

while let Some(data) = f.read() {

// process the data

}

f.close().unwrap();

// can still get a runtime error,

// but represented as a None

f.read().unwrap();

f.close().unwrap();

}

Figure 7. Example of the enum-based file state machine.

These runtime panics can be turned into compile-time errors by encoding each
state as a distinct type, and then only attaching the appropriate methods to
each type. Figure 8 shows one such implementation with `FileRead` and
`FileEof` states. The other key idea is that each state transition method
invalidates the input object and returns the new state as a part of the
output. In Rust, this concept is represented by taking ownership of the input
state via `self` as opposed to a reference via `&self` or `&mut self`.

For example, the signature of `read` consumes the input file, and then uses an
`Either` type to represent that one of two state transitions is possible.
Either the file self-transitions to the Read state, or the file transitions to
the Eof state. For the `close` method, no state is returned because because no
operations exist on the Close state.

⬇

struct FileRead { fd: Descriptor }

struct FileEof { fd: Descriptor }

enum Either<L, R> { Left(L), Right(R) }

\parimpl FileRead {

fn open(path: &str) -> FileRead {

FileRead { fd: sys_open(path) }

}

\parfn read(mut self) ->

Either<(FileRead, Vec<u8>), FileEof>

{

if sys_eof(&self.fd) {

Either::Right(FileEof { fd: self.fd })

} else {

let buf = sys_read(&mut self.fd);

Either::Left((self, buf))

}

}

\parfn close(mut self) {

sys_close(&mut self.fd);

}

}

\parimpl FileEof {

fn close(mut self) {

sys_close(&mut self.fd);

}

}

Figure 8. File state machine with typestate encoding.

⬇

fn main() {

let mut f: FileRead = FileRead::open(”f.txt”);

let f: FileEof = loop {

f = match f.read() {

Either::Left((f, data)) => {

// … process the data …

f

}

Either::Right(f) => break f

}

};

// cannot call f.read() on FileEof

f.close();

// cannot call f.close() again since f is moved

}

Figure 9. Example of the typestate-based file state machine.

A drawback of the approach in Figure 8 is that both struct fields like `fd`
and methods like `close` are duplicated between the two state structs. Figure
10 shows an alternative approach. We return to having a single `File` type,
but now it is parameterized222 The ``File¡S¿— definition needs a field
``PhantomData¡S¿— to prevent the compiler from complaining about an unused
type, but we omit that detail here.  by a state type `S`. The implementation
is similar to Figure 8, except every instance of `FileRead` is replaced by
`File<Read>`. Additionally, the `close` method is now implemented once using a
generic `impl` block over all states.

⬇

struct Read;

struct Eof;

struct File<S> { fd: Descriptor }

\parimpl File<Read> {

fn open(path: &str) -> File<Read> {

/* Essentailly same implementation */

}

\parfn read(mut self) ->

Either<(File<Read>, Vec<u8>), File<Eof>>

{

/* Essentially same implementation */

}

}

\parimpl<S> File<S> {

fn close(mut self) {

sys_close(&mut self.fd);

}

}

Figure 10. File state machine with generic typestate encoding.

Commentary: State machines are an extremely common idiom in system design, so
it is a good instance of a kind of domain pattern that deserves treatment as a
design pattern. The typestate technique has a long history (Strom and Yemini,
1986; Aldrich et al., 2009), and recent work has shown how typestate can be
embedded in the type systems of existing languages (Bernardy et al., 2017;
Duarte and Ravara, 2021). Libraries for session types use similar mechanisms
(Pucella and Tov, 2008; Jespersen et al., 2015).

In the Rust ecosystem, typestate can be found in hardware programming, e.g. to
represent the state of GPIO pins on a board as in the rppal library
(golemparts/rppal) for Raspberry Pi. Typestate is also used by the Rocket web
server framework ([1,3]https://rocket.rs////) to represent the different
states of a server while it is starting up.

###  2.3. Parallel Lists

Schema: Two Lists of heterogeneous elements with a Parallel Relation between
the elements.

Examples: `printf` (string format holes should match the arguments to fill the
holes), web routes (a URL with multiple parameters should match the server
callback receiving those parameters).

Case study: Consider a `printf`-style string formatter which takes a template
List (string literals and holes) and an argument List (values to stringify
into the holes). Figure 11 shows a simple implementation of printf (ignoring
template parsing).

⬇

enum FElem {

Str(String),

Arg

}

\parfn format(

tpl: Vec<FElem>, mut args: Vec<&dyn ToString>

) -> String {

tpl.into_iter()

.map(|elem| match elem {

FElem::Str(s) => s,

FElem::Arg => args.remove(0).to_string(),

})

.collect()

}

Figure 11. Formatting with enum/vector encoding.

⬇

fn main(){

// Correct usage

let tpl = vec![

FElem::Str(”Hello ”.into()), FElem::Arg];

let args = vec![&”World”];

assert_eq!(”Hello World”, format(tpl, args));

\par// Panics with too few arguments

format(

vec![FElem::Str(”Hello ”.into()), FElem::Arg],

vec![]

);

\par// Silently ignores too many arguments

format(

vec![FElem::Str(”Hello ”.into()), FElem::Arg],

vec![&”World”, &”Again”]

);

}

Figure 12. Example of enum/vector-encoded formatter.

An API client can use this interface incorrectly which results in runtime
errors. Figure 12 shows how too few arguments will cause a runtime panic
(because `Vec::remove` will panic if there are no elements in the vector).
More insidiously, extra arguments are simply ignored.

The key observation is that printf has a Parallel Relation between the
template and arguments. The number of `Var` holes should match the size of the
`args` vector. (A more sophisticated model might also specify that type-
specific formatting modifiers like `".1f"` should only be used for floats.)

To catch user mistakes at compile-time, the type system must be aware of the
length and type of elements in each list. One technique for this is the
heterogeneous list, or h-list. An h-list is a list of elements with mixed
types whose size is known at compile-time. Figure 13 shows how to implement a
type-safe formatter using h-lists.

⬇

struct FStr(String);

struct FArg;

\parstruct HNil;

struct HCons<H, T> { head: H, tail: T }

\partrait Format<Args> {

fn format(&self, args: Args) -> String;

}

\parimpl Format<HNil> for HNil {

fn format(&self, _args: HNil) -> String {

””.to_string()

}

}

\parimpl<ArgList, FmtList> Format<ArgList>

for HCons<FStr, FmtList>

where FmtList: Format<ArgList>

{

fn format(&self, args: ArgList) -> String {

let HCons { head: FStr(head), tail } = self;

head.to_string() + &tail.format(args)

}

}

\parimpl<T, ArgList, FmtList> Format<HCons<T, ArgList>>

for HCons<FArg, FmtList>

where FmtList: Format<ArgList>, T: ToString,

{

fn format(&self, args: HCons<T, ArgList>)

-> String

{

args.head.to_string() \+

&self.tail.format(args.tail)

}

}

Figure 13. Printf with h-list encoding.

⬇

fn main() {

let tpl = hlist![FStr(”Hello ”.into()), FArg];

let args = hlist![”World”];

assert_eq!(”Hello World”, tpl.format(args));

\par// Type error with too few args

tpl.format(hlist![])

\par// Type error with too many args

hlist![].format(hlist![”extra”])

}

Figure 14. Example of h-list-encoded printf.

The core h-list uses an inductive cons-list representation of `HNil` and
`HCons<H, T>` types. For example, lines 2-3 of Figure 14 show the creation of
h-lists through an `hlist!` macro. The type of `tpl` is `HCons<FStr,
HCons<FArg, HNil>>`. The formatting function is then expressed as an inductive
computation over the template and argument h-lists. Unfortunately, the
implementation is far less straightforward than the enum/vector encoding in
Figure 11. In short, the computation is defined through the `format` method
wrapped in the `Format` trait. This trait is implemented for template h-lists,
i.e. h-lists whose head types are either `FArg` or `FStr`. The base case of
`HNil` is the empty string (lines 11-15). The inductive case of `HCons<FStr,
...>` (lines 17-25) extracts the inner string from `FStr` and recurses.

The key is the inductive case of `HCons<FArg, ...>` (lines 27-37) which
captures the parallelism between the template and argument lists. The `Format`
trait is only implemented when the argument list is an `HCons<T, ...>` where
`T: ToString`. The implementation converts `T` to a string, and then recurses
on both `self.tail` (the format list) and `args.tail` (the argument list). The
resulting design catches the issues in Figure 12 at compile-time, as shown in
Figure 14. Passing both too many and too few arguments results in a type
error.

Commentary: The Parallel List pattern is a good example of the trade-off
between complexity and safety. The enum/vector encoding is simpler to read for
the implementor, but it can lead to more bugs at runtime. However, although
the h-list approach catches bugs, the type errors can potentially be
incomprehensible, especially to novices.

Kiselyov et al. (2004) pioneered the h-list approach for Haskell, which has
since been adopted by libraries such as Servant (Mestanogullari et al., 2015).
H-lists are used in Rust by the web server library Warp
(https://github.com/seanmonstar/warpgithub.com/) and a popular MySQL client
(https://github.com/blackbeam/rust-mysql-simplegithub.com/). Many Rust
libraries like Diesel ([1,3]https://diesel.rs////) and Bevy
([1,3]https://bevyengine.org////) emulate h-lists by implementing a trait for
all tuples up to some size $N$, usually $N=16$ or $32$. However, this approach
seriously reduces the comprehensibility of type errors (rust-lang/rfcs#2397).
Yet another approach would be language-level variadic generics, but that
feature is unlikely to be implemented in Rust soon (rust-lang/rfcs#376).

###  2.4. Registry

Schema: Objects that map Keys to heterogeneous Values, and users can register
Keyed Requests for Values.

Examples: Event systems (callbacks associated with event names), dependency
injection (named component injected into functions requesting components by
name).

Case study: Consider an event system that contains events (the Value) with
names (the Key), such as `OnClick` to represent a mouse click. Clients can
register callbacks for an event (the Keyed Request) which can be triggered
with an event of the same name. The system should be open-world—the set of
events can be extended by the API client.

A straightforward encoding of this model (e.g., as you can find in
Javascript’s DOM API) would represent event names as strings and event
listeners as functions consuming a dynamically-typed event payload. Figure 15
shows the Rust implementation of this model.

⬇

type Listener = Box<dyn Fn(&dyn Any)>;

\par#[derive(Default)]

struct Events {

listeners: HashMap<String, Vec<Listener>>

}

\parimpl Events {

fn register(&mut self, ev: &str, f: Listener) {

self.listeners.entry(ev.into())

.or_default().push(f);

}

\parfn trigger(&self, ev: &str, data: &dyn Any) {

if let Some(fs) = self.listeners.get(ev) {

for f in fs { f(data); }

}

}

}

Figure 15. Event registry with string-key encoding.

⬇

struct OnClick { mouse_x: usize, mouse_y: usize }

let mut events = Events::default();

\par// Correct example of register and trigger usage

events.register(”click”, Box::new(|ev| {

let ev = ev.downcast_ref::<OnClick>().unwrap();

assert_eq!(ev.mouse_x, 1);

}));

let ev = OnClick { mouse_x: 1, mouse_y: 3 };

events.trigger(”click”, &ev);

\par// Error #1: Wrong event name at register time

events.register(”clack”, …);

\par// Error #2: Wrong event type in callback

events.register(”click”, Box::new(|ev| {

let ev = ev.downcast_ref::<OnKeyPress>().unwrap();

}));

\par// Error #3: Wrong event name at trigger time

events.trigger(”clack”, …);

\par// Error #4: Wrong event type passed to trigger

events.trigger(”click”, &OnKeyPress { /* … */ });

Figure 16. Example usage of the string-key event encoding.

In this implementation, an event listener is a boxed function consuming `&dyn
Any`, the Rust trait for dynamic typing. An event registry is a hashmap from
strings to vectors of listeners. However, this implementation shifts
significant complexity and risk onto the API client. Figure 16 shows an
example client usage. Observe that the event listener must assert that the
event payload is typed as `OnClick` via the `downcast_ref` method. The
`register` and `trigger` calls must both use a matching `"click"` string. The
`trigger` call must also provide a payload of the appropriate type. If the API
client messes up any of these conditions, a runtime error will occur.

To develop a safer alternative, the key idea is to unify the representation of
event-identity in the API. Rather than using strings to talk about types, we
instead use the type directly, facilitated with the `TypeId` API that provides
a unique, hashable identifier for any type. Figure 17 shows an implementation
of `Events` that maps from type IDs to type-erased vectors of listeners. The
`register` and `trigger` methods no longer take a string event name as input,
but instead use the generic type `E` to refer to events.

⬇

trait Listener<E> = Fn(&E) -> () + ’static;

type ListenerVec<E> = Vec<Box<dyn Listener<E>>>;

\par#[derive(Default)]

struct Events {

listeners: HashMap<TypeId, Box<dyn Any>>

}

\parimpl Events {

fn register<E: ’static, F: Listener<E>>(

&mut self, f: F

) {

let fs = self.listeners

.entry(TypeId::of::<ListenerVec<E>>())

.or_insert_with(||

Box::new(Vec::<ListenerVec<E>>::new()));

fs.downcast_mut::<ListenerVec<E>>().unwrap()

.push(Box::new(f));

}

\parfn trigger<E: ’static>(&self, ev: &E) {

let fs_opt = self.listeners

.get(&TypeId::of::<ListenerVec<E>>());

if let Some(fs) = fs_opt {

let fs = fs.downcast_ref::<ListenerVec<E>>()

.unwrap();

for f in fs { f(ev); }

}

}

}

Figure 17. Event registry with type-key encoding.

Figure 18 shows an example usage of this alternative API. Observe that all the
previous failure points are gone. A callback’s payload must be consistent with
the associated event. A triggered event’s payload must also be consistent with
the associated event. Any typos are caught by the compiler.

⬇

struct OnClick { mouse_x: usize, mouse_y: usize }

let mut events = Events::default();

\parevents.register(|ev: &OnClick| {

assert_eq!(ev.mouse_x, 1);

});

let ev = OnClick { mouse_x: 1, mouse_y: 3 };

events.trigger(&ev);

\par// Can’t associate this with OnClick

events.register(|ev: &OnKeyPress| { /* … */ });

\par// Only triggers OnKeyPress callbacks

events.trigger(&OnKeyPress { /* … */ });

\par// Typos caught by the compiler

events.trigger(&OnClack { /* … */ });

Figure 18. Example usage of the type-key event encoding.

Commentary: The string-key event system is an instance of the broader problem
of “stringly-typed” systems. For example, most developers learn early on that
a fixed domain of objects is better represented by an enumerated type rather
than a string. But that lesson can be difficult to extrapolate into open-world
domains like an event system. Typed design patterns like the Registry can
highlight the mechanisms needed in such a case, like the `TypeId` API.

In the Rust ecosystem, typed registries can be found in many crates. The
Matrix client for Rust (https://github.com/matrix-org/matrix-rust-
sdkgithub.com/) uses a typed registry for event handling. The Bevy game engine
([1,3]https://bevyengine.org////) uses a typed registry for implementing a
typed entity-component-system architecture. The Shaku library
(https://github.com/AzureMarker/shakugithub.com/) provides a generic
dependency injection framework using typed registries. An implementation of
the Liquid template language in Rust (https://github.com/cobalt-org/liquid-
rustgithub.com/) uses typed registries to hold external plugins. The core data
structure that maps type IDs to boxed values can be found neatly encapsulated
in the AnyMap library (https://github.com/chris-morgan/anymapgithub.com/).

##  3\. Related Work

Having now seen four patterns in full detail, we should step back and consider
how this style of presentation relates to prior work on teaching functional
system design. Several books articulate design patterns for individual
functional languages: Scala Design Patterns (Hunt, 2013), Functional
Programming Patterns in Scala and Clojure (Bevilacqua-Linn, 2013), Scala
Functional Programming Patterns (Khot, 2015), Haskell Design Patterns (Lemmer,
2015), Scala Design Patterns (Nikolov, 2016), and Functional Design and
Architecture (Granin, 2020).

These books do not articulate design patterns in the same sense I use within
this paper. For example, much of the content of these books is (a)
reimplementing GoF patterns like visitors, (b) explaining standard library
APIs like monoids and functors, or (c) explaining basic functional programming
concepts like currying. That content is assuredly valuable to its readers, but
I do not envision that the $N^{\text{th}}$ tutorial on monads should be
considered a functional design pattern.

My philosophy is more ideologically aligned with books that articulate a
modeling-oriented design practice. For example, How to Design Programs
(Felleisen et al., 2018), Domain Modeling Made Functional (Wlaschin, 2017),
and Type-Driven Development with Idris (Brady, 2017) all fall under this
umbrella. The difference between these books and the present work is, to an
extent, stylistic. These books present a monolithic narrative that is intended
to be consumed linearly from the first to the last page. But this style is
less well-suited to demand-driven learning where a developer may want to
simply find the best patterns for the problem at hand.

##  4\. Discussion

One goal of this paper is to advance my particular vision for functional
design patterns. But another is to prompt a discussion within the relevant
academic and industrial circles about the key question: what kinds of
knowledge, if any, ought to be articulated as typed functional design
patterns? Or put another way, what do developers need to know that isn’t
currently documented about how to design effective systems in functional
languages?

To that end, we should briefly consider the negative space of issues
unaddressed by this paper. For instance, this paper has focused primarily on
design patterns that catch incorrect programs at compile-time. But performance
is also an important aspect of system design. Within the Rust community, there
are excellent resources for how to profile and optimize small pieces of code
like The Rust Performance Book (Nethercote, 2020). However, there are
comparatively few resources for how to architect a system to trade-off
correctness, performance, maintainability, compile-times, etc. at larger
scales. As just one example of a performance pattern, many Rust libraries use
interning strategies (with a range of implementations) to reduce the memory
footprint of commonly-allocated objects. Such performance patterns deserve to
be documented in their own right.

Regardless, I believe it is high time to revisit design patterns now that the
functional era is upon us. I hope to be a part of writing Functional Design
Patterns, and I invite you to join me in making a Gang of more than just One.

## References

  * (1)
  * whe (2011) 2011\.  Where are all the functional programming design patterns?  https://softwareengineering.stackexchange.com/q/89273.
  * Aldrich et al. (2009) Jonathan Aldrich, Joshua Sunshine, Darpan Saini, and Zachary Sparks. 2009.  Typestate-Oriented Programming. In _Proceedings of the 24th ACM SIGPLAN Conference Companion on Object Oriented Programming Systems Languages and Applications_ (Orlando, Florida, USA) _(OOPSLA ’09)_. Association for Computing Machinery, New York, NY, USA, 1015–1022.  https://doi.org/10.1145/1639950.1640073
  * Bernardy et al. (2017) Jean-Philippe Bernardy, Mathieu Boespflug, Ryan R. Newton, Simon Peyton Jones, and Arnaud Spiwack. 2017.  Linear Haskell: Practical Linearity in a Higher-Order Polymorphic Language.  _Proc. ACM Program. Lang._ 2, POPL, Article 5 (dec 2017), 29 pages.  https://doi.org/10.1145/3158093
  * Bevilacqua-Linn (2013) Michael Bevilacqua-Linn. 2013\.  _Functional Programming Patterns in Scala and Clojure_.  The Pragmatic Bookshelf.
  * Brady (2017) Edwin Brady. 2017\.  _Type-Driven Development with Idris_.  Manning, New York, USA.
  * Duarte and Ravara (2021) José Duarte and António Ravara. 2021.  Retrofitting Typestates into Rust. In _Proceedings of the 25th Brazilian Symposium on Programming Languages_ (Joinville, Brazil) _(SBLP ’21)_. Association for Computing Machinery, New York, NY, USA, 83–91.  https://doi.org/10.1145/3475061.3475082
  * Evans (2003) Eric Evans. 2003\.  _Domain-driven design_.  Addison-Wesley Educational, Boston, MA.
  * Felleisen et al. (2018) Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, and Shriram Krishnamurthi. 2018\.  _How to design programs: an introduction to programming and computing_.  MIT Press.
  * Gamma et al. (1994) Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. 1994.  _Design patterns_.  Addison Wesley, Boston, MA.
  * Gibbons (2006) Jeremy Gibbons. 2006\.  Design Patterns as Higher-Order Datatype-Generic Programs. In _Proceedings of the 2006 ACM SIGPLAN Workshop on Generic Programming_ (Portland, Oregon, USA) _(WGP ’06)_. Association for Computing Machinery, New York, NY, USA, 1–12.  https://doi.org/10.1145/1159861.1159863
  * Granin (2020) Alexander Granin. 2020\.  _Functional Design and Architecture_.  Leanpub.
  * Hunt (2013) John Hunt. 2013\.  _Scala Design Patterns_.  Springer, Pennsylvania, USA.
  * Jespersen et al. (2015) Thomas Bracht Laumann Jespersen, Philip Munksgaard, and Ken Friis Larsen. 2015.  Session Types for Rust. In _Proceedings of the 11th ACM SIGPLAN Workshop on Generic Programming_ (Vancouver, BC, Canada) _(WGP 2015)_. Association for Computing Machinery, New York, NY, USA, 13–22.  https://doi.org/10.1145/2808098.2808100

  * Khot (2015) Atul S. Khot. 2015\.  _Scala Functional Programming Patterns_.  Packt Publishing, Birmingham, UK.
  * Kiselyov et al. (2004) Oleg Kiselyov, Ralf Lämmel, and Keean Schupke. 2004\.  Strongly Typed Heterogeneous Collections. In _Proceedings of the 2004 ACM SIGPLAN Workshop on Haskell_ (Snowbird, Utah, USA) _(Haskell ’04)_. Association for Computing Machinery, New York, NY, USA, 96–107.  https://doi.org/10.1145/1017472.1017488
  * Lemmer (2015) Ryan Lemmer. 2015\.  _Haskell Design Patterns_.  Packt Publishing, Birmingham, UK.
  * Mestanogullari et al. (2015) Alp Mestanogullari, Sönke Hahn, Julian K. Arni, and Andres Löh. 2015.  Type-Level Web APIs with Servant: An Exercise in Domain-Specific Generic Programming. In _Proceedings of the 11th ACM SIGPLAN Workshop on Generic Programming_ (Vancouver, BC, Canada) _(WGP 2015)_. Association for Computing Machinery, New York, NY, USA, 1–12.  https://doi.org/10.1145/2808098.2808099
  * Nethercote (2020) Nicholas Nethercote. 2020\.  The Rust Performance Book.  https://nnethercote.github.io/perf-book/.
  * Nikolov (2016) Ivan Nikolov. 2016\.  _Scala Design Patterns_.  Packt Publishing, Birmingham, UK.
  * Norvig (1998) Peter Norvig. 1998\.  Design Patterns in Dynamic Languages.  https://www.norvig.com/design-patterns/.
  * Pucella and Tov (2008) Riccardo Pucella and Jesse A. Tov. 2008.  Haskell Session Types with (Almost) No Class.  _SIGPLAN Not._ 44, 2 (sep 2008), 25–36.  https://doi.org/10.1145/1543134.1411290
  * Rumelhart (1980) David Rumelhart. 1980\.  Schemata: The building blocks of cognition.  In _Theoretical Issues in Reading Comprehension_. Routledge.
  * Strom and Yemini (1986) Robert E. Strom and Shaula Yemini. 1986.  Typestate: A programming language concept for enhancing software reliability.  _IEEE Transactions on Software Engineering_ SE-12, 1 (1986), 157–171.  https://doi.org/10.1109/TSE.1986.6312929
  * Wlaschin (2017) Scott Wlaschin. 2017\.  _Domain Modeling made Functional. Tackle Software Complexity with Domain-Driven Design and F#_.  The Pragmatic Bookshelf.