functional でもっと便利に tabularray

<!-- # functional でもっと便利に tabularray -->

:::note info
この記事は [TeX & LaTeX Advent Calendar 2023][advent] の 5 日目の記事です。4 日目は [doraTeX][] さんでした。6 日目は [CareleSmith9][] さんです。
:::

[advent]: https://adventar.org/calendars/9305 "TeX ＆ LaTeX Advent Calendar 2023 - Adventar"
[doraTeX]: https://doratex.hatenablog.jp/entry/20231204/1701624166 "学習塾でのLaTeX活用事例集 ～［改訂第9版］LaTeX美文書作成入門の補足～ - TeX Alchemist Online"
[CareleSmith9]: http://circle9tym.blog.fc2.com/blog-entry-432.html "[TeX]「TeX Live ドキュメント案内」のリンク切れドキュメント案内 - East Opera 2023"

今年の TeX & LaTeX Advent Caleandar 2023 の重点テーマは「**(La)TeXで幸せになる方法**」であり、アドベントカレンダーが始まったことを伝える [はてな記事][hatena-advent] では以下のように書かれていました。

[hatena-advent]: https://zrbabbler.hatenablog.com/entry/2023/12/01/200415 "アドベントがはじまった ― \\begin{texadvent2023} - マクロツイーター"

> 徹底的に **tabularray** を使いこなして幸せ :blush: になるのもよし、

と言うことで、[tabularray][] パッケージにおける functional ライブラリを利用して表作成の一部を自動化することで幸せになる方法を紹介します。

[tabularray]: https://ctan.org/pkg/tabularray "CTAN: Package tabularray"

実は、tabularray パッケージを用いて増減表を書く方法の記事の最後で “functional ライブラリを利用すれば、セルの内容を評価して矢印を自動的に判定させることも出来る気がします。” と書いていました。

https://qiita.com/Yarakashi_Kikohshi/items/dc83ded22cf6977e8fcf

[qiita-zougen]: https://qiita.com/Yarakashi_Kikohshi/items/dc83ded22cf6977e8fcf "LaTeX で増減表を書きたい #LaTeX - Qiita"

これらを受けて本記事では、functional ライブラリを利用して増減表の矢印を自動判定させることを最終目標とします。
また、tabularray については既にある程度よく知っているものとします。

> 増減表とは、高校数学で扱うグラフの概形をつかむための表です。
>
> 例：
> ![zougen-image-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590705/e6a6af97-8948-514e-1bcd-03dc7192c483.png)

## functional ライブラリとは

[functional]: https://ctan.org/pkg/functional "CTAN: Package functional"
[expl3]: https://ctan.org/pkg/expl3 "CTAN: Package expl3"

functional ライブラリは [functional][] パッケージを tabularray に導入するためのライブラリです。

functional パッケージは [expl3][] や LuaTeX の代替となる LaTeX2e 用の関数型プログラミングインターフェースです。
Lua のように外部言語に依存せず [^functional-expl3]、かつ expl3 と異なり関数の評価が内側から外側に行います。（ちょっとこの辺りは僕には詳しく説明できないため、誰かに譲ります）

[^functional-expl3]: functional は expl3 で実装されているので、expl3 が利用できるエンジンであれば使えます。

簡単に言えば、外部言語なしに Lua みたいな書き方でプログラミングできるパッケージです。

### functional の基本

functional は expl3 によって実装されていることもあり、いくつかの類似点があります。
まず、これらの類似点を表にしておきます。

|                  |     functional     |      expl3       |
| ---------------: | :----------------: | :--------------: |
|       関数の開始 | `\IgnoreSpacesOn`  | `\ExplSyntaxOn`  |
|       関数の終了 | `\IgnoreSpacesOff` | `\ExplSyntaxOff` |
|         型の種数 |         10         |        19        |
|   関数の命名規則 |   lowerCamelCase   |    snake_case    |

<!-- |   ローカル変数名 |   `l` から始まる   |  `l` から始まる  |
| グローバル変数名 |   `g` から始まる   |  `g` から始まる  | -->

`\IgnoreSpacesOn` [^ignorespaces] \~`\IgnoreSpacesOff` の間では、expl3 と同じように行末の処理や半角スペースを気にする必要はない一方で、半角スペースを明示的に `~` を用いて表現する必要があります。[^IgnoreSpacesOnOff]

[^ignorespaces]: `\IgnoreSpacesOn` は LaTeX 標準の [`\ignorespaces`][latexref-ignorespaces] に似ていますが、まったく意味が異なります。
[^IgnoreSpacesOnOff]: 実は、functional では関数を必ずしも `\IgnoreSpacesOn`\~`\IgnoreSpacesOff` で利用する必要はありません。とは言っても、行末の処理を考えることは面倒になることがあるため、`\IgnoreSpacesOn`\~`\IgnoreSpacesOff` の間で関数を定義するべきです。

[latexref-ignorespaces]: http://latexref.xyz/_005cignorespaces-_0026-_005cignorespacesafterend.html "\ignorespaces & \ignorespacesafterend (LaTeX2e unofficial reference manual (September 2023))"

また、基本的な関数は expl3 から導入されています。そのため、expl3 に慣れている人であればそれなりに使いやすいかも知れません。

新たな関数を定義するには `\prgNewFunction` を使い、戻り値に `\prgReturn` を使います。

### 型

functional には以下の 10 の型とそれぞれの接辞があります。

[expl3-wtsn]: https://blog.wtsnjp.com/2018/04/28/expl3-for-tex-users/#%E5%A4%89%E6%95%B0%E3%81%AE%E3%82%AB%E3%82%BF%E3%83%81 "§ 変数のカタチ - TeX 言語者のための expl3 入門 | ラング・ラグー"

|  接辞   | 型名               |
| :-----: | :----------------- |
| `bool`  | 真偽値             |
|  `str`  | 文字列             |
|  `tl`   | トークンリスト     |
|  `int`  | 整数               |
|  `fp`   | 浮動点小数         |
|  `dim`  | ディメンション     |
| `clist` | コンマ区切りリスト |
|  `seq`  | シーケンス         |
| `prop`  | プロパティリスト   |
| `regex` | 正規表現           |

例えば、整数型における整数値をセットするための関数は <code>\\<strong>int</strong>Set</code> となっています。
以降では、型の接辞を `‹type›` と表現します。

<!-- 特に、LaTeX はトークンと呼ばれる塊で記述されます。そのため、`\LaTeX` などのコマンド等はトークンリスト型として扱う必要があります。 -->

### 変数

変数は `\‹type›New` によって宣言されます。
宣言される変数の変数名は自由に決めることが出来ますが、ローカル変数は `l` から、グローバル変数は `g` から始まる必要があります。
これは expl3 と類似しています。

また、`\lTmpaStr` のような規定変数があり、ローカル変数は <code>\lTmp<em>n</em>‹type›</code> で表現され、グローバル変数は <code>\gTmp<em>n</em>‹type›</code> で表現されます。*`n`* には `a`・`b`・`c`・`i`・`j`・`k` のいずれかが入ります。

したがって、`\lTmpaStr` は文字列型 *a* 番目のローカル変数です。

## tabularray における functional ライブラリ

functional ライブラリは `\usepackage{tabularray}` の後で `\UseTblrLibrary` を使って、導入します。

```latex
\usepackage{tabularray}
\UseTblrLibrary{functional}
```

### セルの評価

tabularray パッケージで作成された表に `process` キーを用いることで、セル内を評価する関数を表に適用することが出来ます。

例えば、適当に定義された関数 `\function` を表に適用するには次のようにします。

```latex
\begin{tblr}{
    process = \function,
    % some style settings
  }
  % table contents
\end{tblr}
```

### 特定のセル情報の取得・反映

tabularray パッケージには、特定のセルの内容を取得する `\cellGetText` や特定のセルの内容やスタイルを決定する `\cellSetText`・`\cellSetStyle` があります。

- セルの内容の取得：
    - `\cellGetText{<rownum>}{<colnum>}`
- セルの内容の書き込み：
    - `\cellSetText{<rownum>}{<colnum>}{<text>}`
- セル・行・列のスタイルの指定：
    - `\cellSetStyle{<rownum>}{<colnum>}{<style>}`
    - `\rowSetStyle{<rownum>}{<style>}`
    - `\columnSetStyle{<colnum>}{<style>}`

<!-- Set 系のコマンドは `\prgReturn` しなくても戻り値を適当に処理してくれるようです。（特に明文化されていませんが、挙動としてはそうらしい） -->

例えば、2 行 4 列目のセルの内容を取得する場合は、次のように指定します。

```latex
\cellGetText{2}{4}
```

また、表の行数・列数は `rowcount`・`colcount` によって取得できます。ただし、実際には `\arabic{rowcount}` などとする必要があります。

そのため、3 行最終列目のセルに内容を書き込む場合は、次のように指定します。

```latex
\cellSetText{3}{\arabic{colcount}}{New~cell~content}
```

## 増減表の矢印を自動的に判定する

<!-- やっと本題。 -->

tabularray で作成された増減表の矢印を自動的に判定するコードを書きます。

今回作成したい関数は、増減表の矢印を増減表の微分行の正負符号から自動的に判別することです。
すなわち、次のような表を書いているときに、表のコンテンツとして矢印用のコマンドを明示的に書かないことを目標としています。

```latex
\begin{tblr}{
    process = \judgeArrow,
    % some style settings
  }
  x    & \cdots & -2  & \cdots & 1           & \cdots & 4  & \cdots \\
  f'   & +      & 0   & -      & -           & -      & 0  & +      \\
  f''  & -      & -   & -      & 0           & +      & +  & +      \\
  %%   ここのセルに自動的に矢印が出てくるようにしたい
  %%     ↓              ↓                      ↓             ↓
  f(x) &        & 5   &        & \frac{3}{4} &        & -2 &        \\
\end{tblr}
```

### 判定方法の概要

増減表は一次微分のみのものと二次微分までのものの 2 種類あります。そのため、今回はそれぞれに対応する関数を作成します。
加えて、表の行数からどちらの関数が適用されるかを条件分岐させます。

反復処理で各列の微分行のセル内容を取得して、正負によって条件分岐させ矢印を決定します。

今回、評価方法は `+`・`-` をそのまま文字列として取り扱いました。
また、`+`・`-` 以外の文字列の場合には、セル内にあるままのトークン列が出力されるようにします。

### 完成したコード

完成したコードは次のようになりました。

`\judgeDiagonalArrow` が一次微分のみの増減表用、
`\judgeRoundedArrow` が二次微分までの増減表用の判定関数です。

`\judgeArrow` は表の行数を評価して `\judgeDiagonalArrow` と `\judgeRoundedArrow` に条件分岐させます。
そのため、実際に利用する関数は `\judgeArrow` です。

判定結果で出力される `\diagonalArrow**` や `\roundedArrow**` は、[前回の記事][qiita-zougen] で TikZ を用いて描いた矢印を利用しています。

```latex
\IgnoreSpacesOn
\prgNewFunction \judgeDiagonalArrow { } {
  % 2 列目から最終列まで反復試行
  \intStepOneInline {2} {\arabic{colcount}} {
    % 2 行 ##1 列目のセルの内容を lTmpaStr に格納
    \strSet \lTmpbStr { \cellGetText {2} {##1} }
    % lTmpaStr の内容が + か - かそれ以外かを条件分岐
    \strCaseF {\strUse \lTmpaStr} {
        % + または - に応じた矢印を lTmpiTl に格納
        {+} { \tlSet \lTmpiTl {\evalWhole{\diagonalArrowNE}} }
        {-} { \tlSet \lTmpiTl {\evalWhole{\diagonalArrowSE}} }
      }
      {
        % + でも - でもない場合は 3 行 ##1 列目のセルの内容を lTmpiTl に格納
        \tlSet \lTmpiTl { \evalWhole{\cellGetText {3} {##1}} }
      }
    % 3 行 ##1 列目のセルに lTmpiTl を書き込む
    \cellSetText {3} {##1} { \tlUse \lTmpiTl }
  }
}
\prgNewFunction \judgeRoundedArrow { } {
  % 2 列目から最終列まで反復試行
  \intStepOneInline {2} {\arabic{colcount}} {
    % 2 行 ##1 列目のセルの内容を lTmpbStr に格納
    \strSet \lTmpbStr { \cellGetText {2} {##1} }
    % 3 行 ##1 列目のセルの内容を lTmpcStr に格納
    \strSet \lTmpcStr { \cellGetText {3} {##1} }
    % lTmpbStr と lTmpcStr を連結して lTmpaStr とする
    \strConcat \lTmpaStr \lTmpbStr \lTmpcStr
    % lTmpaStr の内容が ++、+-、-+、-- かそれ以外かを条件分岐
    \strCaseF {\strUse \lTmpaStr} {
        % ++、+-、-+、-- に応じた矢印を lTmpiTl に格納
        {++} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowRU}} }
        {+-} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowUR}} }
        {-+} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowDR}} }
        {--} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowRD}} }
      }
      {
        % ++、+-、-+、-- のいずれでもない場合は 3 行 ##1 列目のセルの内容を lTmpiTl に格納
        \tlSet \lTmpiTl { \evalWhole{\cellGetText {4} {##1}} }
      }
    % 4 行 ##1 列目のセルに lTmpiTl を書き込む
    \cellSetText {4} {##1} { \tlUse \lTmpiTl }
  }
}
\prgNewFunction \judgeArrow { } {
  % 行数が 3 か 4 か条件分岐
  \intCase {\arabic{rowcount}} {
    % 3 であれば judgeDiagonalArrow を実行
    {3} {\judgeDiagonalArrow}
    % 4 であれば judgeRoundedArrow を実行
    {4} {\judgeRoundedArrow}
  }
}
\IgnoreSpacesOff
```

実際に、次のような増減表に `\judgeArrow` 関数を適用させてみると、ちゃんと矢印の含まれた増減表を取得できます。

```latex
\begin{tblr}{
    width = {0.7\linewidth},
    hline{1,Z} = {0.08em},
    hline{2,Y}, vlines,
    colspec = {*{8}{X[1,c]}},
    columns = { mode = dmath },
    process = \judgeArrow,
  }
  x    & \cdots & -2  & \cdots & 1           & \cdots & 4  & \cdots \\
  f'   & +      & 0   & -      & -           & -      & 0  & +      \\
  f''  & -      & -   & -      & 0           & +      & +  & +      \\
  f(x) &        & 5   &        & \frac{3}{4} &        & -2 &        \\
\end{tblr}
```

![zougen-image-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590705/49749786-4e45-8a51-df82-2c27ebfcf4b8.png)

# 余談

tabularray パッケージの functional ライブラリを利用する方法を紹介しました。
表作成はセルの内容に応じてスタイルを変更することもあるので、自動化することでより幸せになることでしょう。

tabularray パッケージは、[第 9 版 LaTeX 美文書作成入門][latex-bibunsho] でも取り扱われている使いやすい表作成パッケージです。
表にたくさん触れる機会がある人や、表のコンテンツとスタイルを分離したいと考えている人、セル結合の必要がある人等、ぜひ一度使ってみることをオススメします。

[latex-bibunsho]: https://gihyo.jp/book/2023/978-4-297-13889-9 "［改訂第9版］LaTeX美文書作成入門：書籍案内 | 技術評論社"

tabularray パッケージに関するざっくりとした使い方に関して、以下の記事もあります。こちらも是非参照してください。

https://qiita.com/Yarakashi_Kikohshi/items/b645de659cbfe8c12b36

functional パッケージは、このパッケージ自体が「誰が使ってるねん」と思うくらいインターネッツ検索してもヒットしません。（特に日本語！）[^search-functional]
LaTeX パッケージについて多数投稿されているあの [天地有情][tenchi] さんでさえ functional パッケージは紹介されていませんでした :cry:

[tenchi]: https://konoyonohana.blog.fc2.com/blog-entry-414.html "天地有情 [LaTeX] 最新版：公開済みパッケージ一覧表(アルファベット順)"

[^search-functional]: Google で ["functional"][google-functional] と検索しても絶対に上手く出てきません。（そもそも、ネーミング的に厳しいです）["functional tabularray"][google-functional-tabularray] や変数の ["ltmpaint"][google-ltmpaint] などと検索する必要があります。

[google-functional]: https://www.google.com/search?q=functional "functional - Google 検索"
[google-functional-tabularray]: https://www.google.com/search?q=functional+tabularray "functional tabularray - Google 検索"
[google-ltmpaint]: https://www.google.com/search?q=ltmpaint "ltmpaint - Google 検索"

どちらのパッケージも、日本語ネット情報はあまり多くありません。興味がある方はぜひ使って記事として公開してください。（特に functional……）

ちなみに、[functional][github-functional] と [tabularray][github-tabularray] の作者は同じ人です。

[github-functional]: https://github.com/lvjr/functional "lvjr/functional: Intuitive functional programming interface for LaTeX2"
[github-tabularray]: https://github.com/lvjr/tabularray "lvjr/tabularray: Typeset tabulars and arrays with LaTeX3"

## functional の tips

増減表の矢印を判定させる関数を書く際に個人的に詰まったところを tips として紹介します。

### 変数を関数内で利用する

`\strCase` のような条件分岐でテスト文字列にローカル変数 (`\lTmpaStr`) を用いる場合、そのままでは変数として利用できません。

例えば、次のようなコードを書いてみます。

```latex
\IgnoreSpacesOn
\strSet \lTmpaStr {abc}
\strCaseF {\lTmpaStr} {
  {123} {Numeral}
  {abc} {Alphabet}
  {αβγ} {Greek}
}{No~match}
\IgnoreSpacesOff
```

3 行目の `\strCaseF {\lTmpaStr} {` のテスト文字列は “\\lTmpaStr” となっています。これは変数 `\lTmpaStr` に格納された内容をテスト文字列として利用しているのではなく、文字列 “\\lTmpaStr” そのものです。
そのため、“No match” が出力されます。

これを回避するには、テスト文字列内でも `\strUse` する必要があります。

```latex
\IgnoreSpacesOn
\strSet \lTmpaStr {abc}
\strCaseF {\strUse \lTmpaStr} {
  {123} {Numeral}
  {abc} {Alphabet}
  {αβγ} {Greek}
}{No~match!}
\IgnoreSpacesOff
```

これによって、`\lTmpaStr` がテスト文字列に利用されます。

### 変数に格納された LaTeX コマンドを出力する

functional を扱っていて少し困ったことがありました。それは変数に格納された LaTeX コマンドが出力されないことです。

例えば、ローカル変数 `\lTmpaStr` に `\LaTeX` を格納して出力しようと次のように書いてみます。
LaTeX ロゴが出力されることが期待されますが、これによって出力される文字列は “\\LaTeX” です。

```latex
\IgnoreSpacesOn
\strSet \lTmpaStr { \LaTeX }
\strUse \lTmpaStr
\IgnoreSpacesOff
```

上の例での間違いは 2 点です。

- LaTeX コマンドはトークンリスト型である
- `\evalWhole` を用いて展開した状態で格納する必要がある

これらを踏まえると、次のように書くことで LaTeX ロゴが出力されるようになります。

```latex
\IgnoreSpacesOn
\tlSet \lTmpaTl { \evalWhole{\LaTeX} }
\tlUse \lTmpaTl
\IgnoreSpacesOff
```

### 反復処理のカウンタ

functional では、反復処理を行う `\‹type›StepInline` や `\intStepOneInline` があります。

[ifthen][] パッケージ等ではカウンタを適当に定義してから反復処理を書きますが、functional では `#1` がカウンタを担います。（expl3 でもそう）

[ifthen]: https://ctan.org/pkg/ifthen "CTAN: Package ifthen"

そのため、反復処理内で反復処理を行う場合カウンタが重複してしまうため、`#` が連続するようになります。
すなわち、外側の反復処理のカウンタでは `#1` を使うのに対して、内側の反復処理のカウンタでは `##1` を使います。
さらに、3 重の反復処理を行う場合、最内の反復処理のカウンタは `####1`（`#` が 4 つ）です。[^newcommand]

[^newcommand]: 実は `\newcommand` でも入れ子にすることで `#` が連続することが知られています。（[参照][texforum-p9645]）

    参照しているコメントでは 2 重の `\newcommand` についてのみしか言及されていませんが、3 重の `\newcommand` を実際に行ってみると最内の `\newcommand` の引数は `####1` となっています。

    ```latex
    \newcommand{\test}[1]{
      \newcommand{\Test}[1]{
        \newcommand{\TEST}[1]{
          #1, ##1, ####1
        }
      }
    }

    \test{a} \Test{b} \TEST{c}
    ```

[texforum-p9645]: https://okumuralab.org/tex/mod/forum/discuss.php?d=1669#p9645 "QA: newcommand内のnewcommandの引数 - 2015年 09月 27日(日曜日) 21:10 - Z. R. の投稿"

これを踏まえると、N 重の反復処理の最内のカウンタは 2N 個の `#` が連続します。

これに加えて、functional では `\prgNewFunction` を用いて関数を定義することが出来ます。これももちろん引数を `#1` として表現します。
そのため、`\prgNewFunction` 内で反復処理する場合も `#` を連続させるため、ふつうに `##1` や `####1` が登場します。

## もう少し増減表を簡単に

`\judgeArrow` 関数を利用した際の表のコンテンツ部分を見ると、`\cdots` は省略できそうです。

`\cdots` そのものを明示的に入力しなくても、1 行目が空白または `...` があるようなセルには `\cdots` が自動的に挿入されるようなコードを `\judgeArrow` に追加しておいても良いかもしれません。

例えば、次のような `\varDots` 関数を書きます。

```latex
\prgNewFunction \varDots { m } {
  % 1 行 #1 列目のセルの内容を lTmpaStr に格納
  \strSet \lTmpaStr { \cellGetText {1} {#1} }
  % lTmpaStr が null または .{3}、\cdots の場合は true コードを実行
  \strCaseT {\strUse \lTmpaStr} {
    {} {}
    {.} {}
    {..} {}
    {...} {}
    {\cdots} {}
  } {
    % lTmpiTl に \cdots を格納
    \tlSet \lTmpiTl {\evalWhole{\cdots}}
    % 1 行 #1 列目に lTmpiTl を書き込む
    \cellSetText {1} {#1} { \tlUse \lTmpiTl }
  }
}
```

これを `\judgeDiagonalArrow`・`\judgeRoundedArrow` 関数内に挿入しておけば、`\cdots` も省略できます。

完全に空白がイヤな場合は、`.` や `...` を入れておくだけでも `\cdots` になるようにしてあります。

<details>
<summary><code>\cdots</code> を省略できる <code>\judgeArrow</code> 関数（折りたたみ）</summary>

```latex
\IgnoreSpacesOn
\prgNewFunction \varDots { m } {
  \strSet \lTmpaStr { \cellGetText {1} {#1} }
  \strCaseT {\strUse \lTmpaStr} {
    {} {}
    {.} {}
    {..} {}
    {...} {}
    {\cdots} {}
  } {
    \tlSet \lTmpiTl {\evalWhole{\cdots}}
    \cellSetText {1} {#1} { \tlUse \lTmpiTl }
  }
}
\prgNewFunction \judgeDiagonalArrow { } {
  \intStepOneInline {2} {\arabic{colcount}} {
    \varDots{##1}
    \strSet \lTmpaStr { \cellGetText {2} {##1} }
    \strCaseF {\strUse \lTmpaStr} {
        {+} { \tlSet \lTmpiTl {\evalWhole{\diagonalArrowNE}} }
        {-} { \tlSet \lTmpiTl {\evalWhole{\diagonalArrowSE}} }
      }
      {
        \tlSet \lTmpiTl { \evalWhole{\cellGetText {3} {##1}} }
      }
    \cellSetText {3} {##1} { \tlUse \lTmpiTl }
  }
}
\prgNewFunction \judgeRoundedArrow { } {
  \intStepOneInline {2} {\arabic{colcount}} {
    \varDots{##1}
    \strSet \lTmpbStr { \cellGetText {2} {##1} }
    \strSet \lTmpcStr { \cellGetText {3} {##1} }
    \strConcat \lTmpaStr \lTmpbStr \lTmpcStr
    \strCaseF {\strUse \lTmpaStr} {
        {++} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowRU}} }
        {+-} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowUR}} }
        {-+} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowDR}} }
        {--} { \tlSet \lTmpiTl {\evalWhole{\roundedArrowRD}} }
      }
      {
        \tlSet \lTmpiTl { \evalWhole{\cellGetText {4} {##1}} }
      }
    \cellSetText {4} {##1} { \tlUse \lTmpiTl }
  }
}
\prgNewFunction \judgeArrow { } {
  \intCase {\arabic{rowcount}} {
    {3} {\judgeDiagonalArrow}
    {4} {\judgeRoundedArrow}
  }
}
\IgnoreSpacesOff
```

</details>

`\cdots` を省略できる `\judgeArrow` 関数を利用すると、次のように書くことで済むようになります。

```latex
\begin{tblr}{
    width = {0.7\linewidth},
    hline{1,Z} = {0.08em},
    hline{2,Y}, vlines,
    colspec = {*{8}{X[1,c]}},
    columns = { mode = dmath },
    process = \judgeArrow,
  }
  x    &   & -2  &   & 1           &   & 4  &   \\
  f'   & + & 0   & - & -           & - & 0  & + \\
  f''  & - & -   & - & 0           & + & +  & + \\
  f(x) &   & 5   &   & \frac{3}{4} &   & -2 &   \\
\end{tblr}
```

ここまで簡略化できればかなり楽でしょう。ただ、どれくらい増減表を書きたい人がいるのかは不明ですが……