LISTSERV mailing list manager LISTSERV 16.0

Help for LATEX-L Archives


LATEX-L Archives

LATEX-L Archives


LATEX-L@LISTSERV.UNI-HEIDELBERG.DE


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Proportional Font

LISTSERV Archives

LISTSERV Archives

LATEX-L Home

LATEX-L Home

LATEX-L  October 2011

LATEX-L October 2011

Subject:

Re: Church booleans

From:

Lars Hellström <[log in to unmask]>

Reply-To:

Mailing list for the LaTeX3 project <[log in to unmask]>

Date:

Wed, 19 Oct 2011 23:42:21 +0200

Content-Type:

multipart/mixed

Parts/Attachments:

Parts/Attachments

text/plain (142 lines) Parts/Attachments

multipart/appledouble (142 lines) , application/applefile (142 lines) , churchbool.dtx (1 lines)

Bruno Le Floch skrev 2011-10-19 18.16:
>> A better formatting would be
>>
>> \bool_if:nTF {
>>      \bool_pred:n{\l_my_first_bool}&&  (
>>         \bool_pred:n{\l_my_second_bool}&&
>>         ! \bool_pred:n{\l_my_third_bool}
>>      )
>> }
>
> Still unreadable in my view, because the \bool_pred:n add no
> information, and are just there to make TeX happy. Since we can avoid
> them altogether, let's do it.

We can also avoid these corny infix expressions altogether... ;-)

> \bool_if:nTF
>    {
>      \l_my_first_bool
>      &&  (
>         \l_my_second_bool
>        &&  ! \l_my_third_bool
>      )
>    }
>
>> :) But maybe the problem is that&&, (, ), !, and || do not really stand out
>> from the background of braces and backslashes (far less than against the
>> background of alphanumeric identifiers you'd encounter in C)? Fortanish
>> .AND., .OR., and .NOT. would be more eye-catching, but the parentheses are
>> probably a lost cause readability-wise.
>
> I find&&  and || to be more visible than AND and OR in fact (probably
> a matter of syntax highlighting in the editor).

I find it unlikely that an editor with syntax highlighting for LaTeX would 
assign special highlighting to || and !, unless someone has specially 
reconfigured it to do so.

>> Well, it depends on the parsing scheme one uses. If instead going for
>> delimited-argument style subformula grabbing, then it wouldn't matter how
>> many tokens an expression terminal (predicate) consists of, and as a
>> side-effect operation priority becomes straightforward (the operation you
>> split at first gets the lowest priority). What would be tricky for this
>> approach is the handling of parentheses, since in that case there are two
>> distinct possibilities for "the next token of interest here", but I think it
>> is doable (first split on one, then try to split on the second, and treat
>> the combination of the outcomes as a case).
>
> The other problem with this approach is that my working copy with
> Church booleans is now catcode agnostic, while delimited arguments
> would require one particular catcode. You are right on the other
> arguments for that approach.

Catcodes for ADNORT and () don't tend to change much.

>> I believe one could preferably structure the whole thing as an expand-only
>> rewrite of infix boolean expression to Church-style compositions of
>> booleans. It probably wouldn't be good at catching certain syntax errors,
>> though.
>
> That's a pretty big change. I need some time to ponder it. (And in any
> case, changes won't happen before a few weeks from now.)

Well, changes could as a matter of fact happen tonight already, since I had 
just completed my implementation of it when I received your mail. See 
attached file (I hope it gets through). I've probably picked strange names 
for some macros, but I think the post-colon parts are acceptable.

Here's an example:

\if_bool_expr:nTF{
    ( NOT \l_my_first_bool OR \IfFileExists{latex.ltx} )
    AND \l_my_second_bool
}{Evaluates~to~true.}{Evaluates~to~false.}

This works. And it's done using macros. *Nothing* but macros.

>> Consider a command whose role is similar to that of the 2e \makelabel: A
>> user-definable command which gets its argument(s) from more basic levels of
>> LaTeX, and is supposed to do something in a configurable way. ((In the
>> future all such commands should be template keys, you say? Why, yes, it may
>> well be. Template instances will often be defined with \ExplSyntaxOff, I
>> think.)) Suppose further that one of these arguments is a boolean. ((Poor
>> design? Well, such things will happen; it's an open system.)) Now, if said
>> boolean is a Church boolean (effectively \use_i:nn or \use_ii:nn), then it
>> can be used directly to select between two pieces of code, e.g. like
>>
>> \def\makesomething#1#2{% Assuming \ExplSyntaxOff
>>      % #1 is some text
>>      % #2 is the boolean
>>      #1%
>>      #2{ \thetheorem}{}%
>>      .\ %
>> }
>
> What about \let \ifthenelse \bool_if:nTF ? That doesn't assume
> anything about the internals, and allows precisely what you describe
> (and is slightly more general, since the user can now use boolean
> expressions).

I'm not particularly fond of that. In particular, requiring the use of a 
command that does fancy expression parsing just for the sake of even using a 
boolean seems highly wasteful.

>>> We could provide \bool_and:nn etc. (or some variation thereof). One
>>> problem is where to stop: here you've used the three argument variant
>>> \add:nnn, but we should then provide a four argument variant, etc.
>>
>> Even if you include everything up to the nine argument forms, you'll end up
>> with fewer macros in total than for the alternative. ;-)
>
> True with the current code, I think, but my new code doesn't need two
> separate branches, so that statement becomes false :). Then it _is_
> true that 18 cs is not that much. However,
>
> \bool_if:nTF
>    {
>       \bool_and:nnnnnnn % n?
>          \l_i_bool
>          \l_ii_bool
>          \l_iii_bool
>          \l_iv_bool
>          \l_v_bool
>          \l_vi_bool
>          \l_vii_bool
>          \l_viii_bool
>    }

Provided that the booleans are really Church booleans, that \bool_if:nTF 
serves no purpose.

> is not exactly obvious to update if a boolean is added. The&&  version
> is simple: add "&&  \l_last_bool".

Anyone writing expressions with that many clauses deserve a little 
difficulty in updating them; usually, it is a sign that one is making things 
far too complicated, and should rethink one's approach to the problem. :-)

Lars Hellström




% % \iffalse %<*driver> \documentclass{ltxdoc} \catcode`\_=12 \begin{document} \DocInput{churchbool.dtx} \end{document} %</driver> % \fi % % % \title{Church boolean implementations} % \author{Lars Hellstr\"om} % \maketitle % % \section{Preliminaries} % % Since I'll probably be working within a \LaTeXe\ system when % developing the following, I'll need to provide the \LaTeX3 commands % I'll use separately. % % \begin{macrocode} %<*2e> \def\ExplSyntaxOn{% \catcode 126=10 \relax % tilde is a space char. \catcode 32=9 \relax % space is ignored \catcode 9=9 \relax % tab also ignored \endlinechar =32 \relax % endline is space \catcode 95=11 \relax % underscore letter \catcode 58=11 \relax % colon letter } \def\ExplSyntaxOff{% \catcode 126=13 \relax % tilde is active. \catcode 32=10 \relax % space is space \catcode 9=10 \relax % tab also space \endlinechar =13 \relax % endline is ^^M \catcode 95=8 \relax % underscore is subscript \catcode 58=12 \relax % colon is other } \ExplSyntaxOn \def\cs_new:Npn{\long\def} % Fake: Ignores checking new status \def\cs_set_eq:NN #1 { \let #1=~ } \def\q_stop{\string\q_stop} % Isn't this a much safer way to \def\q_mark{\string\q_mark} % construct a quark? %</2e> % \end{macrocode} % % % % \section{The real stuff} % % \begin{macrocode} %<*code> % \end{macrocode} % % \subsection{The booleans themselves} % % The rules of the game are that a ``boolean'', in wide sense, is % anything with an overall syntax of |:TF|, i.e., % \begin{quote} % \meta{boolean}\marg{true code}\marg{false code} % \end{quote} % will eventually end up as either \meta{true code} or \meta{false % code}, depending on what value the boolean ``evaluates to''. % % \begin{macro}{\if_true:TF} % \begin{macro}{\if_false:TF} % The constant boolean values are therefore identical to the % classical helper macros |\@firstoftwo| and |\@[log in to unmask] % \begin{macrocode} \cs_new:Npn \if_true:TF #1 #2 { #1 } \cs_new:Npn \if_false:TF #1 #2 { #2 } % \end{macrocode} % \end{macro}\end{macro} % % \begin{macro}{\if_and:nnTF} % \begin{macro}{\if_or:nnTF} % \begin{macro}{\if_not:nTF} % The nice thing about Church booleans is that boolean expressions % in terms of them can be computed purely using macro expansion. % Concretely, % \begin{quote} % |\if_and:nnTF|\marg{b1}\marg{b2}\marg{true code}\marg{false code} % \end{quote} % expands to \meta{true code} iff both \meta{b1} and \meta{b1} % evaluate to true, and expands to \meta{false code} otherwise; % \begin{quote} % |\if_or:nnTF|\marg{b1}\marg{b2}\marg{true code}\marg{false code} % \end{quote} % expands to \meta{false code} iff both \meta{b1} and \meta{b1} % evaluate to false, and expands to \meta{true code} otherwise; % \begin{quote} % |\if_not:nTF|\marg{b1}\marg{true code}\marg{false code} % \end{quote} % expands to \meta{false code} iff \meta{b1} evaluate to true, and % expands to \meta{true code} otherwise. % % All evaluation is short-curcuit, i.e., if the result is known % from evaluating \meta{b1} alone, then \meta{b2} will not be % evaluated. % \begin{macrocode} \cs_new:Npn \if_and:nnTF #1 #2 { #1 {#2} {\if_false:TF} } \cs_new:Npn \if_or:nnTF #1 #2 { #1 {\if_true:TF} {#2} } \cs_new:Npn \if_not:nnTF #1 { #1 {\if_false:TF} {\if_true:TF} } % \end{macrocode} % \end{macro}\end{macro}\end{macro} % % \begin{macro}{\if_and:nnnTF} % \begin{macro}{\if_or:nnnTF} % Higher arity conjunctions can be constructed by nesting the % binary ones, but also in a single step. % \begin{macrocode} \cs_new:Npn \if_and:nnnTF #1 #2 #3 { #1 {#2 {#3} {\if_false:TF} } {\if_false:TF} } \cs_new:Npn \if_or:nnnTF #1 #2 #3 { #1 {\if_true:TF} {#2 {\if_true:TF} {#3} } } % \end{macrocode} % Note in particular that the arguments don't need to be copied. % Exclusive or, should one wish to implement it, is not quite so % nice. % \end{macro}\end{macro} % % % \subsection{Church booleans as variables} % % Since Church booleans aren't ordinary values, but rather functions, % one might feel uncertain as to how feasible it is to store such a % boolean value in a variable; getting this wrong could instead end % up storing the expression for a boolean, and cause it to be % reevaluated each time used. However, the solution is extremely % simple. % % \begin{macro}{\bool_set:Nn} % The effect of % \begin{quote} % |\bool_set:Nn|\marg{cs}\marg{boolean} % \end{quote} % is to evaluate the \meta{boolean} and set the control sequence % \meta{cs} to either |\if_true:TF| or |\if_false:TF| accordingly. % \begin{macrocode} \cs_new:Npn \bool_set:Nn #1 #2 { #2 { \cs_set_eq:NN #1 \if_true:TF } { \cs_set_eq:NN #1 \if_false:TF } } % \end{macrocode} % \end{macro} % % % \subsection{Infix expressions of Church booleans} % % Although Church booleans are most at home within a prefix notation, % it turns out to also be possible to form infix expressions of them, % within a suitable parsing framework. The boolean expression syntax % supported here is % \begin{description} % \def\makelabel#1{\meta{#1}~\ensuremath{\longleftarrow}} % \item[expression] % \meta{term} $\mid$ \meta{term} |OR| \meta{expression} % \item[term] % \meta{factor} $\mid$ \meta{factor} |AND| \meta{term} % \item[factor] % \meta{terminal} $\mid$ |NOT| \meta{factor} % \item[terminal] % \meta{Church boolean} $\mid$ |(| \meta{expression} |)| % \end{description} % (Note the parentheses in the last branch.) % % The unexpected contrapositive of the above syntax specification is % that anything which is part of something put forth as an % \meta{expression} and which is not part of an |AND|, |OR|, |NOT|, % |(|, or |)| will be assumed to be part of \meta{Church boolean}. % Typos may therefore lead to highly surprising results\dots % % % \subsubsection{Detecting reserved words} % % The ``reserved words'' in an expression are |AND|, |OR|, |NOT|, % |(|, and |)|. For each of these, it is necessary to have a test for % whether that word occurs in a token sequence (not counting % occurrencies between braces). These tests are based on standard % exploits of trickeries made possible by \TeX's rules for matching % delimited and undelimited arguments. % % \begin{macro}{\if_AND_in:nTF} % This macro is a Church boolean if used as % \begin{quote} % |\if_AND_in:nTF|\marg{expression fragment} % \end{quote} % It evaluates to true (purely by expansion) iff the three token % sequence |AND| occurs unbraced in the \meta{expression fragment}. % \begin{macrocode} \cs_new:Npn \if_AND_in:nTF #1 { \if_AND_in_helper:w #1 AND \q_mark \if_true:TF \q_mark \if_false:TF \q_stop } \cs_new:Npn \if_AND_in_helper:w #1 AND #2 #3 \q_mark #4 #5 \q_stop {#4} % \end{macrocode} % The way it works is that if there is an |AND| in the % \meta{expression fragment}, then in the expansion of % |\if_AND_in_helper:w|, |#1| will consist of everything up to that % |AND|, so |#2#3| will consist of everything up to the first % |\q_mark|, and hence |#4| will be the |\if_true:TF|. If on the other % hand there is no |AND|, then |#1| will consist of the whole % \meta{expression fragment}, |#2| will be the first |\q_mark|, and % |#4| therefore what follows after the second |\q_mark|, namely % |\if_false:TF|. % \end{macro} % % \begin{macro}{\if_OR_in:nTF} % \begin{macro}{\if_NOT_in:nTF} % \begin{macro}{\if_lparen_in:nTF} % \begin{macro}{\if_rparen_in:nTF} % The remaining reserved words are detected in exactly the same way. % \begin{macrocode} \cs_new:Npn \if_OR_in:nTF #1 { \if_OR_in_helper:w #1 OR \q_mark \if_true:TF \q_mark \if_false:TF \q_stop } \cs_new:Npn \if_OR_in_helper:w #1 OR #2 #3 \q_mark #4 #5 \q_stop {#4} \cs_new:Npn \if_NOT_in:nTF #1 { \if_NOT_in_helper:w #1 NOT \q_mark \if_true:TF \q_mark \if_false:TF \q_stop } \cs_new:Npn \if_NOT_in_helper:w #1 NOT #2 #3 \q_mark #4 #5 \q_stop {#4} \cs_new:Npn \if_lparen_in:nTF #1 { \if_lparen_in_helper:w #1 ( \q_mark \if_true:TF \q_mark \if_false:TF \q_stop } \cs_new:Npn \if_lparen_in_helper:w #1 ( #2 #3 \q_mark #4 #5 \q_stop {#4} \cs_new:Npn \if_rparen_in:nTF #1 { \if_rparen_in_helper:w #1 ) \q_mark \if_true:TF \q_mark \if_false:TF \q_stop } \cs_new:Npn \if_rparen_in_helper:w #1 ) #2 #3 \q_mark #4 #5 \q_stop {#4} % \end{macrocode} % \end{macro}\end{macro}\end{macro}\end{macro} % % % % \subsubsection{Parsing parenthesis-free expressions} % % For starters, we will consider parsing expressions without % parentheses. The syntax relevant for this is thus: % \begin{description} % \def\makelabel#1{\meta{#1}~\ensuremath{\longleftarrow}} % \item[nopar-expression] % \meta{nopar-term} $\mid$ % \meta{nopar-term} |OR| \meta{nopar-expression} % \item[nopar-term] % \meta{nopar-factor} $\mid$ % \meta{nopar-factor} |AND| \meta{nopar-term} % \item[nopar-factor] % \meta{Church boolean} $\mid$ |NOT| \meta{nopar-factor} % \end{description} % A straightforward technique for this is to check if the thing we're % parsing contains the reserved word at this level, and if so split % at that word and parse the parts separately, or else reparse the % thing as the next simpler thing. This will lead to subexpressions % being parsed lazily, which is probably a good thing. % % \begin{macro}{\if_noparexpr:nTF} % To illustrate this technique, here is the top level parser for % \meta{nopar-expression}s. Its job is to turn % \begin{quote} % |\if_noparexpr:nTF{|\meta{nopar-term}| OR |^^A % \meta{nopar-expression}|}| % \end{quote} % into % \begin{quote} % |\if_or:nnTF{ \if_noparterm:nTF|\marg{nopar-term} |}{| % |\if_noparexpr:nTF|\marg{nopar-expression} |}| % \end{quote} % and % \begin{quote} % |\if_noparexpr:nTF|\marg{nopar-term} % \end{quote} % into % \begin{quote} % |\if_noparterm:nTF|\marg{nopar-term} % \end{quote} % From this description, the implementation is next to obvious. % \begin{macrocode} \cs_new:Npn \if_noparexpr:nTF #1 { \if_OR_in:nTF{#1}{ \if_noparexpr_split:w #1\q_stop }{ \if_noparterm:nTF{#1} } } \cs_new:Npn \if_noparexpr_split:w #1 OR #2 \q_stop { \if_or:nnTF{ \if_noparterm:nTF{#1} }{ \if_noparexpr:nTF{#2} } } % \end{macrocode} % For slightly larger speed (and reducing the number of tokens), one % could preexpand the |\if_or:nnTF|, making the above instead %\begin{verbatim} % \cs_new:Npn \if_noparexpr_split:w #1 OR #2 \q_stop { % \if_noparterm:nTF{#1} \if_true:TF { \if_noparexpr:nTF{#2} } % % } %\end{verbatim} % \end{macro} % % \begin{macro}{\if_noparterm:nTF} % With the above in mind, the following definition of a macro for % doing terms should hold no surprises. % \begin{macrocode} \cs_new:Npn \if_noparterm:nTF #1 { \if_AND_in:nTF{#1}{ \if_noparterm_split:w #1\q_stop }{ \if_noparfactor:nTF{#1} } } \cs_new:Npn \if_noparterm_split:w #1 AND #2 \q_stop { \if_and:nnTF{ \if_noparfactor:nTF{#1} }{ \if_noparterm:nTF{#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\if_noparfactor:nTF} % For handling |NOT|, we actually do this kind of preexpansion, % since it is so extremely easy. A point of doing this is that it % simplifies a comparison with a parser that would eliminate double % negations before evaluating the terminal boolean; that turns out % to be an unnecessary complication, since even working out whether % we have parsed an even or odd number of |NOT|s in this % \meta{nopar-factor} amounts to at least as much work as the % negations that the above would construct from the whole thing. % \begin{macrocode} \cs_new:Npn \if_noparfactor:nTF #1 { \if_NOT_in:nTF{#1}{ \if_noparfactor_split:w #1\q_stop }{ #1 % \end{macrocode} % Inserting a |\use_i:n| in front of that |#1|, while \emph{not} % wrapping the |#1| in braces, should have the effect of gobbling % all spaces in front of the terminal booleans in an expression. % Spaces following them are gobbled already by some |\if_true:TF| % or |\if_false:TF|. % \begin{macrocode} } } \cs_new:Npn \if_noparfactor_split:w #1 NOT #2 \q_stop { #2 \if_false:TF \if_true:TF } % \end{macrocode} % \end{macro} % % % \subsubsection{Parsing general expressions} % % The idea used for parsing general expressions is to replace % parentheses not containing another parenthesis with a % |\if_noparexpr:nTF| call, since that is a \meta{Church boolean} and % thus syntactically valid at that point; this process is repeated % until no parentheses remain, at which point we have a % \meta{nopar-expression}. % % \begin{macro}{\if_bool_expr:nTF} % When locating a parenthesis to convert, it is convenient to start % with the end of it, as the first right parenthesis in an % \meta{expression} always closes a parenthesis not containing % another parenthesis. % \begin{macrocode} \cs_new:Npn \if_bool_expr:nTF #1 { \if_rparen_in:nTF {#1} { \bool_first_rparen_split:w #1 \q_stop }{ \if_noparexpr:nTF{#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\first_rparen_split:w} % After finding the right parenthesis, one must look for a matching % left parenthesis. % \begin{macrocode} \cs_new:Npn \bool_first_rparen_split:w #1 ) #2 \q_stop { \if_lparen_in:nTF { #1 } { \bool_first_lparen_split:w #1 \q_stop {#2} }{ % \end{macrocode} % The case that there isn't a left parenthesis is an error that % we actually can detect! The only problem is what to do about it, % since we may be in expand-only land here. One way of raising an % error is to refer to an undefined but readably named control % sequence. % \begin{macrocode} \use:c{No~matching~left~parenthesis~in~boolean~expression!} % \end{macrocode} % It may in this situation be tempting to throw away both the |T| % and |F| arguments up ahead, but in the presence of surrounding % macros (e.g.~a |\if_not:nTF|) that can just as well lead to both % the eventual \meta{true-code} and ditto \meta{false-code} being % executed, as well as a jumble of bizarre errors. Just picking one % branch can still lead to further errors, but hopefully not % dramatically many of them. % \begin{macrocode} \if_false:TF } } % \end{macrocode} % \end{macro} % % \begin{macro}{\bool_first_lparen_split:w} % \begin{macro}{\bool_last_lparen_split:w} % The matching left parenthesis we're looking for is the last one % before the previously detected right parenthesis. \TeX\ macros can % only pick out the first occurrence of a token however, so in order % to find the last one it becomes necessary to do some looping by % means of tail recursion. To that end, this macro has the call % syntax % \begin{quote} % |\bool_last_lparen_split:w| \meta{fragment} |\q_stop| % \marg{prefix} \marg{suffix} % \end{quote} % with the token sequence % \begin{quote} % \meta{prefix}|(|\meta{fragment}|)|\meta{suffix} % \end{quote} % an invariant of the loop. Material is however being moved from % \meta{fragment} to \meta{prefix}. % % \begin{macrocode} \cs_new:Npn \bool_last_lparen_split:w #1 ( #2 \q_stop #3 #4 { \if_lparen_in:nTF { #2 } { \bool_last_lparen_split:w #2 \q_stop {#3(#1} {#4} }{ % \end{macrocode} % When there are no more left parentheses in |#2|, then it will be % precisely the \meta{nopar-expression} that the first right % parenthesis ended, so we can now convert it to an % |\if_noparexpr:nTF|. Note that that will still be inserted into % an |\if_bool_expr:nTF|; it will mutate itself to an % |\if_noparexpr:nTF| in due time, when there are no parentheses % left in it. % \begin{macrocode} \if_bool_expr:nTF{ #3 ( #1 \if_noparexpr:nTF{#2} #4 } } } % \end{macrocode} % % There is, however, a complication for the first iteration, in % that the \meta{fragment} at that point is not preceded by a left % parenthesis. Hence we need a separate iteration macro at that % point, with the slightly simpler syntax % \begin{quote} % |\bool_first_lparen_split:w| \meta{fragment} |\q_stop| % \marg{suffix} % \end{quote} % such that it is % \begin{quote} % \meta{fragment}|)|\meta{suffix} % \end{quote} % that is equal to the above invariant token sequence. % % \begin{macrocode} \cs_new:Npn \bool_first_lparen_split:w #1 ( #2 \q_stop #3 { \if_lparen_in:nTF { #2 } { \bool_last_lparen_split:w #2 \q_stop {#1} {#3} }{ \if_bool_expr:nTF{ #1 \if_noparexpr:nTF{#2} #3 } } } %</code> % \end{macrocode} % \end{macro}\end{macro} % % \begin{macrocode} %<2e>\ExplSyntaxOff % \end{macrocode} % % % \section{Tests} % % \begin{macrocode} %<*tests> %<*2e> \documentclass{article} \begin{document} \ExplSyntaxOn %</2e> % \end{macrocode} % % First the expression that was mentioned on \LaTeX-L. % \begin{macrocode} \bool_set:Nn\l_my_first_bool{\if_true:TF} \bool_set:Nn\l_my_second_bool{\if_true:TF} \bool_set:Nn\l_my_third_bool{\if_false:TF} Should~evaluate~to~true.~ \if_bool_expr:nTF { \l_my_first_bool AND ( \l_my_second_bool AND NOT \l_my_third_bool ) } {Evaluates~to~true.} {Evaluates~to~false.} \par \bool_set:Nn\l_my_third_bool{\if_true:TF} Should~evaluate~to~false.~ \if_bool_expr:nTF { \l_my_first_bool AND ( \l_my_second_bool AND NOT \l_my_third_bool ) } {Evaluates~to~true.} {Evaluates~to~false.} \par % \end{macrocode} % % Next an expression meant to exercise all twists and turns of the % commands, also demonstrating that nonexpandable tests are supported. % \begin{macrocode} Should~evaluate~to~true.~ \if_bool_expr:nTF{ ((( NOT \l_my_first_bool OR \IfFileExists{latex.ltx} ))) AND \l_my_second_bool }{Evaluates~to~true.}{Evaluates~to~false.} \par % \end{macrocode} % \begin{macrocode} %<*2e> \ExplSyntaxOff \end{document} %</2e> %</tests> % \end{macrocode} % \endinput

Top of Message | Previous Page | Permalink

Advanced Options


Options

Log In

Log In

Get Password

Get Password


Search Archives

Search Archives


Subscribe or Unsubscribe

Subscribe or Unsubscribe


Archives

July 2019
April 2019
March 2019
February 2019
January 2019
December 2018
November 2018
October 2018
September 2018
August 2018
June 2018
May 2018
April 2018
February 2018
January 2018
December 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
December 2016
July 2016
April 2016
March 2016
February 2016
January 2016
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
October 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
December 2012
November 2012
September 2012
August 2012
July 2012
June 2012
May 2012
March 2012
February 2012
January 2012
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
September 2007
August 2007
June 2007
May 2007
March 2007
December 2006
November 2006
October 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
November 2005
October 2005
September 2005
August 2005
May 2005
April 2005
March 2005
November 2004
October 2004
August 2004
July 2004
May 2004
April 2004
March 2004
February 2004
January 2004
December 2003
October 2003
August 2003
July 2003
June 2003
May 2003
April 2003
March 2003
February 2003
January 2003
December 2002
October 2002
September 2002
August 2002
July 2002
June 2002
March 2002
December 2001
October 2001
September 2001
August 2001
July 2001
June 2001
May 2001
April 2001
March 2001
February 2001
January 2001
December 2000
November 2000
October 2000
September 2000
August 2000
July 2000
May 2000
April 2000
March 2000
February 2000
January 2000
December 1999
November 1999
October 1999
September 1999
August 1999
May 1999
April 1999
March 1999
February 1999
January 1999
December 1998
November 1998
October 1998
September 1998
August 1998
July 1998
June 1998
May 1998
April 1998
March 1998
February 1998
January 1998
December 1997
November 1997
October 1997
September 1997
August 1997
July 1997
June 1997
May 1997
April 1997
March 1997
February 1997
January 1997
December 1996

ATOM RSS1 RSS2



LISTSERV.UNI-HEIDELBERG.DE

Universität Heidelberg | Impressum | Datenschutzerklärung

CataList Email List Search Powered by the LISTSERV Email List Manager