4

I'm trying to write a macro to let me write logic formulae in a more natural syntax. I've come up with a working version which however has a problem when used inside align environments (and in tabular as well).

This is the code:

\documentclass{article}

\usepackage{amsmath}
\usepackage{amssymb}% for \Box
\usepackage{xparse}
\usepackage{xstring}
\usepackage{pgffor}

\makeatletter
\NewDocumentCommand\logic{m}{%
  \def\@formula{#1}%
  \saveexpandmode
  \expandarg
  \foreach \keyword/\operator in \@operators {%
    \StrSubstitute{\@formula}{\keyword}{\operator}[\@temp]%
    \global\let\@formula\@temp
  }%
  \restoreexpandmode
  \@formula
}

% Here the list of recognised syntax with the corresponding commands
\def\@operators{
  []/\Box,
  <>/\Diamond,
  !/\neg,
  &&/\land,
  ||/\lor,
  <->/\leftrightarrow,
  ->/\rightarrow,
  <-/\leftarrow
}
\makeatother

\begin{document}

Here is a valid modal logic formula: $\logic{[]p -> p && <>[]p}$

This is a display modal logic formula:
\begin{align}
 \logic{[]p -> p && <>[]p}
\end{align}

\end{document}

If I comment the second paragraph, the output is the following:

output

However, the same macro used inside the align environment gets totally mad, producing hundreds of error messages.

I was expecting problems when using & which is an active character with special meaning in align. I suppose the problem is that align splits beforehand the content of the line into two parts, \logic{[]p -> p and <>[]p}, which then cause all the troubles. Is that right?

Indeed, if I avoid using & in the formula and comment out the &&/\land line in the @operators macro, the macro works inside align as well.

Note that everything works in equation, using & as well.

Is there a way to make this code work inside align? Or is there a way to achieve the same result that works inside align?

5

I enclosed the \logic definition in an extra set of braces.

Depending on your need for letting information get into or out of the boundaries of \logic, an alternative "brace hack" may be used in lieu of the extra braces. See Understanding Brace Hacks. For example, \DeclareDocumentCommand\logic{m}{\iffalse{\fi...\iffalse}\fi} also works, plus gives the ability for the formula to be surrounded by math with binary/unary information being transmittable across the boundary. See more in SUPPLEMENT.

\documentclass{article}

\usepackage{amsmath}% for `align`
\usepackage{latexsym}% for \Box
\usepackage{xparse}
\usepackage{xstring}
\usepackage{pgffor}

\makeatletter
\DeclareDocumentCommand\logic{m}{{%
  \gdef\@formula{#1}%
  \saveexpandmode
  \expandarg
  \foreach \keyword/\operator in \@operators {%
    \StrSubstitute{\@formula}{\keyword}{\operator}[\@temp]%
    \global\let\@formula\@temp
  }%
  \restoreexpandmode
  \@formula
}}

% Here the list of recognised syntax with the corresponding commands
\def\@operators{
  []/\Box,
  <>/\Diamond,
  !/\neg,
  &&/\land,
  ||/\lor,
  <->/\longleftrightarrow,
  ->/\longrightarrow,
  <-/\longleftarrow
}
\makeatother

\begin{document}

Here is a valid modal logic formula: $\logic{[]p -> p && <>[]p}$

This is a display modal logic formula:
\begin{align}
 \logic{[]p -> p && <>[]p}
\end{align}

\end{document}

enter image description here


SUPPLEMENT: BRACE HACKS

Here is an example of how the brace hack makes a difference. Compare the two cases, the first with extra braces, the 2nd with a brace hack. In the 2nd case, the binary nature of the + communicates with the prior y to provide proper spacing around the +.

\documentclass{article}

\usepackage{amsmath}% for `align`
\usepackage{latexsym}% for \Box
\usepackage{xparse}
\usepackage{xstring}
\usepackage{pgffor}

\makeatletter
\DeclareDocumentCommand\logic{m}{{%
  \gdef\@formula{#1}%
  \saveexpandmode
  \expandarg
  \foreach \keyword/\operator in \@operators {%
    \StrSubstitute{\@formula}{\keyword}{\operator}[\@temp]%
    \global\let\@formula\@temp
  }%
  \restoreexpandmode
  \@formula
}}

% Here the list of recognised syntax with the corresponding commands
\def\@operators{
  []/\Box,
  <>/\Diamond,
  !/\neg,
  &&/\land,
  ||/\lor,
  <->/\longleftrightarrow,
  ->/\longrightarrow,
  <-/\longleftarrow
}
\makeatother

\begin{document}

Here is a valid modal logic formula: $\logic{[]p -> p && <>[]p}$

This is a display modal logic formula:
\begin{align}
 y \logic{+ []p -> p && <>[]p}
\end{align}
\makeatletter
\DeclareDocumentCommand\logic{m}{\iffalse{\fi%
  \gdef\@formula{#1}%
  \saveexpandmode
  \expandarg
  \foreach \keyword/\operator in \@operators {%
    \StrSubstitute{\@formula}{\keyword}{\operator}[\@temp]%
    \global\let\@formula\@temp
  }%
  \restoreexpandmode
  \@formula
\iffalse}\fi}

\begin{align}
 y\logic{+ []p -> p && <>[]p}
\end{align}
\end{document}

enter image description here

  • 1
    I wasn't expecting an answer so easy and perfectly working! Thanks – gigabytes Sep 25 '18 at 15:23
  • 2
    Since you use \global\let\@formula\@temp, you should also do \gdef\@formula{#1}. – egreg Sep 25 '18 at 16:45
  • @egreg Thanks. Is that so there is no confusion over whether a local or a global variable is being employed at any given moment? – Steven B. Segletes Sep 25 '18 at 17:03
  • 1
    It's not simply a question of confusion: with local and global assignments to the same variable, you can exhaust memory. – egreg Sep 25 '18 at 17:17
3

You can use the full power of expl3.

\documentclass{article}

\usepackage{amsmath}
\usepackage{amssymb}% for \Box
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\logic{m}
 {
  \group_align_safe_begin:
  \tl_set:Nn \l_gigabytes_logic_input_tl { #1 }
  \clist_map_function:NN \c_gigabytes_logic_subs_clist \gigabytes_logic_sub:n
  \tl_use:N \l_gigabytes_logic_input_tl
  \group_align_safe_end:
 }
\tl_new:N \l_gigabytes_logic_input_tl
\clist_const:Nn \c_gigabytes_logic_subs_clist
 {
  []/\Box,
  <>/\Diamond,
  !/\neg,
  &&/\land,
  ||/\lor,
  <->/\longleftrightarrow,
  ->/\rightarrow,
  <-/\leftarrow
 }
\cs_new_protected:Nn \gigabytes_logic_sub:n
 {
  \__gigabytes_logic_sub:w #1 \q_stop
 }
\cs_new_protected:Npn \__gigabytes_logic_sub:w #1 / #2 \q_stop
 {
  \tl_replace_all:Nnn \l_gigabytes_logic_input_tl { #1 } { #2 }
 }
\ExplSyntaxOff

\begin{document}

Here is a valid modal logic formula: $\logic{[]p -> p && <>[]p}$

This is a display modal logic formula:
\begin{align}
\logic{[]p -> p && <>[]p}
\end{align}

\end{document}

Points to note:

  1. The & tokens are hidden from align by using \group_align_safe_begin: and \group_align_safe_end:
  2. The routine for substitution is easier and needs no juggling with expansion modes

enter image description here

  • Thanks! Why is DeclareDocumentCommand not suggested “routinely”? – gigabytes Sep 25 '18 at 16:16
  • @gigabytes Because it silently redefines existing commands. – egreg Sep 25 '18 at 16:16
  • Ah you meant in contrast to \New.. and \Renew versions, not in contrast to \newcommand & co. Yes I agree, I copied the snippet from some package cose where it made sense – gigabytes Sep 25 '18 at 16:23
  • I've edited the question to follow your advices that were not directly related to the issue at hand. If you want you may edit the answer as well. – gigabytes Sep 25 '18 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.