8

This is one for the expansion gurus. I'm trying to use switching algebra to show a colleague that you can do that in LaTeX. I would like to use parentheses because it resembles normal function calls (which it isn't). This works for 0 and 1 arguments, but how do I deal with recursive calls and macros? Sometimes I get an extra closing parenthesis. When using recursive calls, #1 and #2 should be fully expanded, I think.

The behavior of \band is that the output is only 1 if both argument are 1, else the result is 0.

\documentclass[a4paper]{article}

\makeatletter
\def\band(#1,#2){\@band{#1}{#2}}
\def\@band#1#2{\ifnum#1=0 0\else\ifnum#2=0 0\else 1\fi\fi}
\makeatother

\begin{document}

\band(0,0) % works
\band(0,1) % works
\band(1,0) % works
\band(1,1) % works

\band(\band(1,1),1) % works
\band(0,\band(1,1)) % doesn't work

\band(\band(1,1),\band(1,1)) % works
\band(\band(0,1),\band(1,1)) % doesn't work

\def\x{1}
\def\y{0}
\band(\y,\band(\x,\x)) % doesn't work
\band(\band(\x,\y),\y) % works


\end{document}
4
  • 1
    if you use an argument delimited by ) then it ends at the first ) so in \band(0,\band(1,1)) #1 and #2 of the first call are 0 and \band(1,1 Simplest is to use {} arguments or you could use \NewDocumentCommand delimited arguments (which test for nesting). Aug 12, 2021 at 20:03
  • 1
    Ah, ok, but I would like to use the inner \band as a whole. Aug 12, 2021 at 20:06
  • 1
    yes I know:-) that would be automatic if you used \band{1}{0} or \band{0,1} syntax, you can use (,) but you have to work harder. Aug 12, 2021 at 20:08
  • 1
    Yes, I know that \band{1}{0} works best (of course), Could you elighten me on the \NewDocumentCommand? (I tried that too, with no luck). Aug 12, 2021 at 20:11

4 Answers 4

8

One simple way to get automatic control of nesting is to make () the tex grouping characters like {}

enter image description here

\documentclass[a4paper]{article}

\makeatletter
\def\band#1{\@band#1\relax}
\def\@band#1,#2\relax{\ifnum#1=0 0\else\ifnum#2=0 0\else 1\fi\fi}
\makeatother

\newenvironment{bands}{\catcode`\(=1\catcode`\)=2 }{}
\begin{document}

\begin{bands}

\band(0,0) % works
\band(0,1) % works
\band(1,0) % works
\band(1,1) % works

\band(\band(1,1),1) % works
\band(0,\band(1,1)) % doesn't work

\band(\band(1,1),\band(1,1)) % works
\band(\band(0,1),\band(1,1)) % doesn't work

\def\x{1}
\def\y{0}
\band(\y,\band(\x,\x)) % doesn't work
\band(\band(\x,\y),\y) % works

  
\end{bands}

\end{document}
4
  • 3
    Is it possible to define completely LaTeX3 definitions for \band that can accommodate the delimiter pair (...) as well as a separating , inside? More broadly, there are 3 "mandatory" delimiters. That's an odd number... how would one manage that type of parameter argument delimitations using LaTeX3 definitions? I can ask a new question if that'll give you some inspiration... :)
    – Werner
    Aug 12, 2021 at 20:29
  • 1
    @Werner I was just wondering, it handles the nesting of () but pulling apart the , without breaking nested cases requires more hand work than I want to do unless I've missed something. Aug 12, 2021 at 20:32
  • 1
    @DavidCarlisle thank you,. A LaTeX3 solution is also welcome. Aug 12, 2021 at 20:36
  • I like your answer as the best. Aug 15, 2021 at 8:09
12

This is a long comment. I just want to point out that pgfmath essentially implements this parser that reads nested functions that look like ln(\x + \y) * sin(\a * mod(\b, 2)). It could be that your colleague will be convinced by

\pgfmathdeclarefunction{band}2{%
    \pgfmathparse{#1 * #2}
}
\pgfmathparse{ band(\x, band(1, \y)) }
The answer is \pgfmathresult
1
8

Programming languages have their features: in TeX you use braces rather than parentheses and balancing nested () is quite tough, if you want to do it expandably.

With braces:

\documentclass[a4paper]{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\band}{m}
 {
  \jodb_band:w #1 \q_stop
 }

\cs_new:Npn \jodb_band:w #1 , #2 \q_stop
 {
  \jodb_band:ee { #1 } { #2 }
 }

\cs_new:Npn \jodb_band:nn #1 #2
 {
  \bool_lazy_and:nnTF { \int_compare_p:n { #1 = 1 } } { \int_compare_p:n { #2 = 1 } }
   { 1 }
   { 0 }
 }
\cs_generate_variant:Nn \jodb_band:nn { ee }

\ExplSyntaxOff

\begin{document}

0: \band{0,0} % works

0: \band{0,1} % works

0: \band{1,0} % works

0: \band{1,1} % works

1: \band{\band{1,1},1} % works

0: \band{0,\band{1,1}} % works

1: \band{\band{1,1},\band{1,1}} % works

0: \band{\band{0,1},\band{1,1}} % works

\def\x{1}
\def\y{0}

0: \band{\y,\band{\x,\x}} % works

0: \band{\band{\x,\y},\y} % works

0: \band{\band{\y,\y},\band{\y,\y}} % works

1: \band{\band{\x,\x},\band{\x,\x}} % works

\end{document}

enter image description here

By the way, there is a much simpler way to do the job:

\documentclass[a4paper]{article}
\usepackage{xfp}

\NewExpandableDocumentCommand{\band}{m}{\fpeval{min(#1)}}
\NewExpandableDocumentCommand{\bor}{m}{\fpeval{max(#1)}}

\begin{document}

and

0: \band{0,0} % works

0: \band{0,1} % works

0: \band{1,0} % works

0: \band{1,1} % works

1: \band{\band{1,1},1} % works

0: \band{0,\band{1,1}} % works

1: \band{\band{1,1},\band{1,1}} % works

0: \band{\band{0,1},\band{1,1}} % works

\def\x{1}
\def\y{0}

0: \band{\y,\band{\x,\x}} % works

0: \band{\band{\x,\y},\y} % works

0: \band{\band{\y,\y},\band{\y,\y}} % works

1: \band{\band{\x,\x},\band{\x,\x}} % works

or

0: \bor{0,0} % works

1: \bor{0,1} % works

1: \bor{1,0} % works

1: \bor{1,1} % works

1: \bor{\bor{1,1},1} % works

1: \bor{0,\bor{1,1}} % works

1: \bor{\bor{1,1},\bor{1,1}} % works

1: \bor{\bor{0,1},\bor{1,1}} % works

%\def\x{1}
%\def\y{0}

1: \bor{\y,\bor{\x,\x}} % works

1: \bor{\bor{\x,\y},\y} % works

0: \bor{\bor{\y,\y},\bor{\y,\y}} % works

1: \bor{\bor{\x,\x},\bor{\x,\x}} % works

\end{document}

This is because the syntax min(<number>,<number>) is allowed in fp-expressions.

enter image description here

1
5

For fun ... how to do this using LuaTeX, which completely ignores the point about programming languages that you are trying to make. I am using ConTeXt syntax, but should be easy to port to LaTeX3 as well:

\startluacode

  userdata = userdata or {}
  userdata.band = function(a,b)
      if a == 0 or b == 0 then
          return 0
      else
          return 1
      end
  end

\stopluacode

\define\band
    {\bgroup
     % Ideally, should use catcode tables
     \catcode`\(=1
     \catcode`\)=2
     \doband}

\def\doband#1{\ctxlua{local band=userdata.band; context(band(#1))}\egroup}

\starttext
\band(0,0) % works
\band(0,1) % works
\band(1,0) % works
\band(1,1) % works

\band(band(1,1),1) 
\band(0,band(1,1)) 
\stoptext

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .