Variable number of arguments: generate alignment characters

alignampersandloopsmacrosparameters

I'm trying to define a command \letin that should produce something that looks as follows.

result

Note that it should support a variable number of "let" arguments and a single "in" argument. For example, the following command

\letin{
  {x = 1}
  {y = 2}
  {z = 3}
}{x*y + z}

should expand to

\begin{aligned}[t]
  \textbf{let }&x = 1,\\
  &y = 2,\\
  &z = 3\\
  \textbf{in }&x*y + z
\end{aligned}

Based on this answer, I came up with the code below. This seems to work, except for a single alignment character that causes an error. The character is inside the body of an \ifx command, which results in the error Incomplete \ifx; .... Is there a way to solve this?

\usepackage{amsmath}

\newif\ifletinsep       % --> this condition is used to prevent a comma for the last "let" argument
\newcommand*{\letin}[2]{% --> this is the command we want
\begin{aligned}[t]
\textbf{let }
\letinsepfalse
\letinscan#1\relax\\
\textbf{in }&#2
\end{aligned}
}
\newcommand{\letinscan}[1]{% --> this command processes the "let" arguments
  \ifx\relax#1\empty
  \else
    \ifletinsep
      , \\
    \else
      \letinseptrue
    \fi
    &#1           % ----> when I remove this alignment character, the command executes without error
    \expandafter\letinscan
  \fi
}

Best Answer

Using your previous display to illustrate the \letin command:

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\letin}{mm}
 {
  \safron_letin:nn { #1 } { #2 }
 }

\seq_new:N \l__safron_letin_assign_seq

\cs_new_protected:Nn \safron_letin:nn
 {
  \seq_set_split:Nnn \l__safron_letin_assign_seq { \\ } { #1 }
  \openup-\jot
  \begin{aligned}[t]
  \textbf{let~} & \seq_use:Nn \l__safron_letin_assign_seq { \\ & } \\
  \textbf{in~} & #2
  \end{aligned}
 }

\ExplSyntaxOff

\begin{document}

\begin{align*}
  \mathit{True} &\mapsto [\mathit{true}] && \textsc{\small Rule 1} \\
  e_1 \mathbin{\mathrm{or}} e_2 &\mapsto
    \letin{
      e_1 \mapsto [a], \\
      e_2 \mapsto [b]
    }{[a \lor b]}
 && \textsc{\small Rule 2}
\end{align*}

\end{document}

enter image description here

Here I avoided enlarging \jot, which doesn't seem necessary and I fix another issue I didn't see previously, namely the wrong usage of \operatorname: you want \mathbin{\mathrm{or}} instead.

You can't have “a variable number of arguments” unless you find a way to terminate them. Using a single argument with \\ as a line separator is more intuitive.

Here the \\ is used to separate off the lines, then it's reinserted between the items with also & for the alignment.