Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to create a list-like environment properties that could be used as such:

\begin{properties}
  \item[Lemonade Rule] \forall \text{lemons} \exists \text{lemonade}
  \item a^2 + b^2 = c^2
  \item[identity] \forall
\end{properties}

The idea is to redefine \item local to the properties environment such that it first ends a math environment if necessary and then starts a new one, optionally typesetting a description. (properties vs. properties* controls reference numbers, as usual.)

Unfortunately, I'm screwing up somewhere in keeping track of my modes. I receive the following error:

ERROR: LaTeX Error: Bad math environment delimiter.

--- TeX said ---

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.90   \item[inverse]
                      \label{def:group:inverse}
--- HELP ---
TeX has found either a math-mode-starting command such as \[ or \(
when it is already in math mode, or else a math-mode-ending command
such as \) or \] while in LR or paragraph mode.  The problem is caused
by either unmatched math mode delimiters or unbalanced braces.

Where am I messing things up? Here is the code: (This is new code based on the information egreg provided; it is pared down a bit in functionality from the original, but the error remains. The old code, an apparent model of bad style, is forever available in the edit log.)

\documentclass{article}
\usepackage{amsmath,xparse,expl3}
\ExplSyntaxOn

\NewDocumentEnvironment { definition } { m }
 {
  % typeset the title of the definition
  \par\noindent\hangindent\parindent
  \textbf{#1}\quad
 }
 {
   % end environment 'definition'
 }



% makes sure math content is centered
\cs_new:Nn \property_do_fill:
 {
  \hskip \textwidth minus \textwidth
 }

% enters math mode and starts a property
% does not typeset a math comment
\cs_new:Nn \property_do_begin:
 {
  \equation
  \quad\bullet
  \property_do_fill:
 }

% enters math mode and starts a property
% does typeset math comment
\cs_new:Nn \property_do_begin:n
 {
  \equation
  \quad\bullet\enspace\text{\slshape #1}
  \property_do_fill:
 }

% ends this property and exists math mode
\cs_new:Nn \property_do_end:
 {
  \property_do_fill:
  \endequation
 }


% declare a new item-like environment 'properties', where each item
% * [mathcomment]   a^2 + b^2 = c^2   (1.3)
\NewDocumentEnvironment { properties } { }
 {
   % Delimits properties
   % starts off by beginning a property, and then redefines itself
   % to end a previous property before starting a new one.
  \DeclareDocumentCommand \item { o }
   {
    \IfValueTF { ##1 }
    { \property_do_begin:n { ##1 } }
    { \property_do_begin:          }

    % redefine \item now to take care of *ending* the last one
    \DeclareDocumentCommand \item { o }
     {
      % end the last property
      \property_do_end:
      % and start a new one
      \IfValueTF { ####1 }
      { \property_do_begin:n { ####1 } }
      { \property_do_begin:            }
     }
   }
 }
 {
   % end environment properties
   % make sure to end the last property
   \property_do_end:
 }

\ExplSyntaxOff

\begin{document}
\begin{definition}{group}
  A group is a set $G$ together
    with a binary operation $*$ on $G$
    that satisfies the following axioms:

  \begin{properties}
  \item[associativity]
    \label{def:group:assoc}
    \forall{a,b,c \in G}{(a * b) * c = a * (b * c)}
  \item[identity]
    \label{def:group:identity}
    \exists e \in G : \forall{a \in G}{a * e = a = e * a}
  \item[inverse]
    \label{def:group:inverse}
    \forall{x \in G}{\exists b \in G : a * b = b * a = e}
  \end{properties}
\end{definition}
\end{document}
share|improve this question
1  
\equation* is two tokens, not one; and you can't abbreviate \begin{equation*} into \equation*. You can't test \IfBooleanTF{#1} in a \cs_new:Nn instruction; that's reserved to \NewDocumentCommand (and the alike commands). While you can do \NewDocumentEnvironment{foo}{s}, the relative \IfBooleanTF will be true when you call \begin{foo}*, not \begin{foo*} (which is undefined). –  egreg Sep 6 '13 at 21:09
    
@egreg — so general misunderstandings all around? I'll see if I can fix it up myself given this information –  Sean Allred Sep 6 '13 at 21:23

1 Answer 1

I'm afraid your code is wrong in so many respects that almost nothing can be salvaged.

First error

\cs_new:Nn \property_do_begin:n
 {
  \IfBooleanTF { #1 } \equation* \equation
  \quad\bullet
  \property_do_fill:
 }

The \IfBooleanTF function makes sense only in the body of \NewDocumentCommand (or alike functions), because it's this function that sets up things so that a * will set the internal boolean to true or false. In \cs_new:Nn the result is basically unpredictable. See the third error for other problems; actually this might work in some cases, because the argument is passed from an "interface" command; but it's considered "bad style" anyway.

Second error

Even if \IfBooleanTF{#1} were successful (which may not), when you use it in

\IfBooleanTF { #1 } \endequation* \endequation

you'd get \equation if a * follows and a * otherwise; in both cases the second \equation would be executed. This is because \equation* is two tokens and you can't abbreviate \begin{equation*} with \equation*. The same for \endequation*, of course.

Third error

With \NewDocumentEnvironment{foo}{<arg specs>}{<start>}{<end>} you're basically doing

\NewDocumentCommand{\foo}{<arg specs>}{<start>}{<end>}
\NewDocumentCommand{\endfoo}{<arg specs>}{<start>}{<end>}

and the arguments passed to \foo after \begin{foo} will be passed also to \endfoo when called by \end{foo}.

Thus \NewDocumentEnvironment{foo}{s} would define only the foo environment, not the foo* environment. When you call

\begin{foo}

your \IfBooleanTF{#1} will evaluate to false. And \begin{foo*} will raise an error. You could call \begin{foo}*, however, and \IfBooleanTF{#1} would evaluate to true.

share|improve this answer
    
Most of this was stemming from my blatant oversight of \begin{env*} vs. \begin{env}*; I've made (what I thought to be) the necessary modifications to my code and simplified it significantly—but to no effect (the same error). Should I edit my question to reflect the new code, or should I ask a new one? –  Sean Allred Sep 7 '13 at 3:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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