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 would like to create a solution environment that prints a solution in the case where an optional argument is set to true (the default) and hides the solution in the case that the argument is false. I tried to use egreg's idea from Is there an "identity" (or "no-op") environment that simply uses its contents unaltered? but my construction already fails due to the optional argument (Illegal parameter number in definition of \endsolution). The idea would be to not show anything (ideally no vertical space would be created either) if we are in the ``false'' case.

Note: I'm aware of other solutions to this problem (see Comparing packages which facilitate typesetting exercises and solutions: exercise vs. answers vs. probsoln) but I am interested to see what I am doing wrong in my construction.

\documentclass{scrartcl}

\usepackage[T1]{fontenc}
\usepackage{ifthen}

% solution environment
\newenvironment{solution}[1][true]{
  \ifthenelse{\boolean{#1}}{\par{\sffamily\bfseries Solution}\par}{\ignorespaces}
}{\ifthenelse{\boolean{#1}}{}{\ignorespacesafterend}}

\begin{document}
This is Exercise 1 with solution.
\begin{solution}
  Solution to Exercise 1
\end{solution}

\bigskip
This is Exercise 2 (without solution).
\begin{solution}[false]
  This should not appear.
\end{solution}

\end{document}
share|improve this question
    
you can't use arguments for an environment in the end statement - there's a way round this using xparse; Why can't the end code of an environment contain an argument? and Passing \newenvironment parameters to the end block? –  cmhughes Apr 19 at 20:26
    
I know you want an answer to your question, but you should have a look at the exsheets package; it truly is great. –  Jubobs Apr 19 at 20:30
    
Thanks, I agree, this is the best package I have seen so far for such tasks. –  Marius Hofert Apr 19 at 20:57

2 Answers 2

up vote 7 down vote accepted

The arguments passed to an environment are not available in the code that is executed at the end. You can get around this by saving them using global declarations in the initialisation code. Also, there is nothing in your example to prevent the body of the environment (i.e. between \begin{solution} and \end{solution}) from being processed in the false case. You can do this using the environ package. In this code, the body of the environment is only processed when the \BODY macro is executed.

\documentclass{scrartcl}
\usepackage[T1]{fontenc}
\usepackage{ifthen}
\usepackage{environ}

% solution environment
\makeatletter
\NewEnviron{solution}[1][true]{
  \gdef\@tmp{#1}
  \ifthenelse{\boolean{#1}}{\par{\sffamily\bfseries Solution}\par\BODY}{\ignorespaces}
}[\ifthenelse{\boolean{\@tmp}}{}{\ignorespacesafterend}]
\makeatother    

\begin{document}
This is Exercise 1 with solution.
\begin{solution}
  Solution to Exercise 1
\end{solution}

\bigskip
This is Exercise 2 (without solution).
\begin{solution}[false]
  This should not appear.
\end{solution}

\end{document}
share|improve this answer
    
Thank you very much for the quick reply + good explanations. –  Marius Hofert Apr 19 at 20:57
    
I posted a follow-up question here (how to use \RenewEnviron instead of \NewEnviron): tex.stackexchange.com/questions/173645/… –  Marius Hofert Apr 26 at 18:48

Here's a solution using the xparse package, and its NewDocumentEnvironment which allows the use of arguments in the \end{environment} code.

The important part is

% solution environment
\NewDocumentEnvironment{solution}{O{true}}{%
    \ifthenelse{\boolean{#1}}{\par{\sffamily\bfseries Solution}\par}{\setbox0=\hbox\bgroup}
    }{%
    \ifthenelse{\boolean{#1}}{}{\egroup}
}

Here's a complete MWE to play with; see Why can't the end code of an environment contain an argument? and Passing \newenvironment parameters to the end block? for further reference.

% arara: pdflatex
% !arara: indent: {overwrite: yes}
\documentclass{article}

\usepackage{xparse}
\usepackage{ifthen}

% solution environment
\NewDocumentEnvironment{solution}{O{true}}{%
    \ifthenelse{\boolean{#1}}{\par{\sffamily\bfseries Solution}\par}{\setbox0=\hbox\bgroup}
    }{%
    \ifthenelse{\boolean{#1}}{}{\egroup}
}

\begin{document}
This is Exercise 1 with solution.
\begin{solution}
    Solution to Exercise 1
\end{solution}

\bigskip
This is Exercise 2 (without solution).
\begin{solution}[false]
    This should not appear.
\end{solution}

\begin{solution}[true]
    This *should*  appear.
\end{solution}

\end{document}
share|improve this answer
1  
I'd use \vbox which allows paragraphs, not \hbox. –  egreg Apr 19 at 21:25
    
@cmhughes: I would like to use \usepackage{ifthen} and define a global variable \newboolean{sol}. I set it to false \setboolean{sol}{false} and sol should be the default for the solution environment, how would one incorporate this? If I use ...{solution}{O{sol}}{... it gives me an error. –  Marius Hofert Apr 23 at 19:51
    
@egreg: I realized a problem with (both \hbox and) \vbox. See here: tex.stackexchange.com/questions/173128/… –  Marius Hofert Apr 23 at 20:54
    
@MariusHofert Yes, of course, if you're devious enough to use the figure environment in a proof. ;-) My proposal for the last question of yours can be easily adapted, I believe. My objection was that \hbox can't work if there is more than simple text and will fail with lists and other things. –  egreg Apr 23 at 20:56
    
@egreg :-) Thanks. Do you know a solution to the problem? Most solution manual contain figures (for better understanding). I like the approach based on xparse, but if I can't use a figure inside a solution environment, this would be quite a drawback –  Marius Hofert Apr 23 at 20:59

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.