2

I am currently using the macro,

\def\<#1: #2: #3\>{\langle #1\;:\if#2\empty\else\;#2\;\fi:\;#3\rangle}

Taken from: http://ctan.org/pkg/tex-ewd.

And I would like to make another similar macro,

\def\<#1 if #2 else #3\>{ \langle #1\; \lhd #2\; \rhd \;#3\rangle }

But this latter one clashes with the former one. It seems I can only have one or the other. Any help on this matter would be greatly appreciated!

Thank-you!

PS. I do not know much about multiple deletmiters, or macros with such structure. Any help, or direction to learning more about this, would be most welcome!

  • Does http://tex.stackexchange.com/questions/200452/macro-parameter-delimited-by-more-than-one-delimiter/200510 help at all? – Joseph Wright Dec 21 '14 at 18:37
  • I read that before posting; it went over my head mostly.

    Should've mentioned, I'm a super novice.

    – Musa Al-hassy Dec 21 '14 at 18:38
  • By the way, you've tagged the question [tag:context] but the question seems to be [tag:tex-core]. Is there a reason for the tag you chose? – Joseph Wright Dec 21 '14 at 18:39
  • It isn't clear what your question is. \< can only have one definition at a time, you need to give a different macro a different name – David Carlisle Dec 21 '14 at 18:39
  • 2
    It would help if you explained what it is you are trying to achieve, as in "I would like a macro that does..." – Steven B. Segletes Dec 21 '14 at 18:39
  • @DavidCarlisle But you can define \< with some look-ahead to choose different paths or to decompose a grabbed #1 in \def\<#1\>, hence my question about the linked question. – Joseph Wright Dec 21 '14 at 18:40
  • 2
    @JosephWright yes probably the definition should be \def\<#1\> with further processing depending on #1but hard to guess. – David Carlisle Dec 21 '14 at 18:41
  • I've attempted to clarify something with an edit. Thank-you. – Musa Al-hassy Dec 21 '14 at 18:49
  • \if#2\empty is almost certainly not what you wanted to test (it tests if the first two tokens of #2 are the same) – David Carlisle Dec 21 '14 at 18:50
  • The macro taken from tex-ewd is as I desire, and I am attempting to replicate similar behaviour while maintaining that macro. – Musa Al-hassy Dec 21 '14 at 18:53
  • @Moses The test \if#2\empty is really wrong! It doesn't do what the macro author believes it does. If #2 is aa it returns true. Unfortunately, bad programming techniques are common; this is one of them. – egreg Dec 21 '14 at 19:02
  • I honestly do not even know how it works, but it does yield the desired results. – Musa Al-hassy Dec 21 '14 at 19:04
  • 1
    @Moses Try \<x: yy: z\>; look and behold! – egreg Dec 21 '14 at 20:27
  • 1
    I know the conversation has moved on, but nobody seems to have said it yet: Welcome to TeX.SX! You can have a look at our starter guide to familiarize yourself further with our format. If you could provide a minimal working example (MWE) showing how you are trying to use these macros, that would probably help people answer. (Not me - I doubt any amount of explanation would help me to answer this question. But me is ignorant; others are wise. Or, at least, they know stuff.) – cfr Dec 21 '14 at 20:43

2 Answers2

3

You're looking for disgrace. A macro should do one job. However, here it is. The usage of \numexpr should be allowed with ConTeXt, but probably there's no need to set up fonts for using \lhd and \rhd

\def\<#1\>{\moseslookforif#1if\moseslookforif}
\def\moseslookforif#1if#2\moseslookforif{%
  \ifx\hfuzz#2\hfuzz
    % no if in the argument
    \mosescolon#1\mosescolon
  \else
    \mosesifelse#1if#2\mosesifelse
  \fi
}

\def\mosescolon#1: #2: #3\mosescolon{%
  \langle #1:\ifx\hfuzz#2\hfuzz\else#2\fi:#3\rangle
}
\def\mosesifelse#1 if #2 else #3if\mosesifelse{%
  \langle #1 \lhd #2 \rhd #3\rangle
}

%%% Code possibly to be omitted, if \lhd and \rhd are already available    
\font\tenlasy=lasy10
\font\sevenlasy=lasy7
\font\fivelasy=lasy5
\newfam\lasyfam
\textfont\lasyfam=\tenlasy
\scriptfont\lasyfam=\sevenlasy
\scriptscriptfont\lasyfam=\fivelasy
\mathchardef\lhd=\numexpr2*"1000+\lasyfam*"100+"01\relax
\mathchardef\rhd=\numexpr2*"1000+\lasyfam*"100+"03\relax
%%% end of code to possibly omit

% the example

$\<a : b : c\>$

$\<x if y else z\>$

\bye

Note that the test \if#2\empty is wrong. It will return true if the second argument to the macro is yy, for instance, which of course is not wanted.

I removed the excess spaces introduced with \; in the original macro.

enter image description here

egreg
  • 1,121,712
  • ConTeXt does not define \lhd and \rhd. Are they supposed to be the same as \triangleleft (0x25C1) and \triangleright (0x25B7)? If so, I can add the appropriate synonyms in char-def.lua – Aditya Dec 22 '14 at 00:04
  • @Aditya They are taken either from lasy10 (the old LaTeX font) or from the AMS symbol font (msam10). – egreg Dec 22 '14 at 00:09
  • Yes, but to be supported out of the box in ConTeXt, they need to be mapped to a Unicode slot in a OpenType math font. They look similar to 0x25C1 and 0x25B7. Would those be the right characters to map to \lhd and \rhd? – Aditya Dec 22 '14 at 03:06
  • @Aditya Yes, those should be the ones. – egreg Dec 22 '14 at 09:28
  • Thank-you for your contributions! After some definition look-up, I think I understand what's going on: you've put a superflous if after the main arg, then you look for an if, if it's followed by a space, an \hfuzz, then you've found the final if and so the main arg has no ifs. Then you look for colons. Thank-you :)

    Now, as I'm an extreme novice, would you please indicate why this approach is a gross blunder and ought to be avoided? I merely wanted similar invocation-notation that mimicked the resulting output.

    Thanks!

    – Musa Al-hassy Dec 22 '14 at 15:18
  • @Moses Notation that mimics the output may be useful, but not if it forces you to overload command syntax. – egreg Dec 22 '14 at 15:27
  • What's wrong with operator overloading? We do it all the time; eg + is used to denote addition in a diverse family of number systems, denotes disjoint union in set theory, and denotes catenation of sequences in programming theory. – Musa Al-hassy Dec 22 '14 at 15:37
  • @Moses Would you use the same function name in C? – egreg Dec 22 '14 at 15:53
  • Maybe not; though I maintain that when appropriate, operator overloading is rather useful. – Musa Al-hassy Dec 22 '14 at 21:58
2

You admit you are a beginner, so we'll start with an analysis of what you've proposed. When you say

\def\<#1: #2: #3\>{\langle #1\;:\if#2\empty\else\;#2\;\fi:\;#3\rangle}

you are defining a macro named \<, meaning that your .tex file must contain this token in order to invoke the macro. Further, the syntax you've defined says that your .tex input must invoke the macro with the following (very restrictive syntax): \<FIRSTARG:SPACE SECONDARG:SPACE THIRDARG\>. If you leave out the spaces, compilation will fail with an error. If any of the arguments themselves contain a space or colon, then that could likewise produce errors (or at list misplaced argument definitions).

So while you can define a macro this way, it seems not convenient for usage. More likely, you want the output to look a certain way, rather than requiring the typed input to appear a certain way. The normal way to define such a macro (in LaTex) for a 3-argument input would be \newcommand\macroname[3]{...macros to produce the desired output using inputs #1, #2, and #3...}. The invocation form is then \macroname{FIRSTARG}{SECONDARG}{THIRDARG}. In this way, braces delimit the inputs, which can now contain colons and spaces without ambiguity,

So if I defined \newcommand\colonangle[3]{\langle #1\;:\if#2\empty\else\;#2\;\fi:\;#3\rangle}, then I could obtain your desired first macro output with the syntax, for example, \colonangle{x}{y}{z}.

Now to your second example. Not only does it also create a macro named \< (which is a duplicate of the prior macro name, but now requiring a different input syntax), it requires you to use words like if and else in the input file. Instead, I propose a second macro definition, to avoid confusion, using a more standard input syntax.

\documentclass{article}
\usepackage{amssymb}
\newcommand\colonangle[3]{\langle #1\;:\if#2\empty\else\;#2\;\fi:\;#3\rangle}
\newcommand\arrowangle[3]{ \langle #1\; \lhd #2\; \rhd \;#3\rangle }
\begin{document}
$\colonangle{A}{B}{C} \ne \arrowangle{A}{B}{C}$
\end{document}

enter image description here

  • You are either missing one \; or you have three extra \; (depending on whether the large spaces are really wanted). – yo' Dec 21 '14 at 22:33
  • @yo' I merely regurgitated the output format that the OP had specified in his question. I myself am not sure of the appropriate spacing. – Steven B. Segletes Dec 21 '14 at 22:44
  • Thank-you for your explanations! I do not know if it is poor practice, but I wanted my invocations to be similar to the desired output. That is, the bracketing and syntax in the source will be similar to that in the result. Is this a poor approach to doing things? If so, please elaborate. – Musa Al-hassy Dec 22 '14 at 15:05
  • 1
    @Moses In the end, it is for you to decide which approach works best. When you LaTeX a lot, you get used to thinking of inputs in braced form, and it makes typing errors easy to debug. As I mentioned, it can become a nuisance to force your input file to contain spaces at particular locations, but you must find what works best for your need. – Steven B. Segletes Dec 22 '14 at 15:14