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 getting a little tired of defining all my mathematical operators with \DeclareMathOperator. Also it is rarely useful to have them as a macro. On the contrary it sometimes leads to macro name collision (e.g. \span). So I came up with the following:

\documentclass{article}
\usepackage{amsmath}
\catcode`\¡=\active
\def¡#1!{\operatorname{#1}}
\begin{document}
    \[e^{ix} = ¡cos! x + i¡sin! x\]
\end{document}

I'd like to get rid of the ! at the end and maybe use \ifmmode, to allow ¡ in normal text. Is that possible? Are there other side effects of my definition I should be aware of?

share|improve this question
    
\newcommand{\op}[1]{\operatorname{#1}}. However, I can't understand the point. –  egreg Feb 8 at 18:11
    
@egreg: Then I would have to write braces around the name. I don't want to write more than if I had used \DeclareMathOperator. –  canaaerus Feb 8 at 18:12
    
How can TeX know where to end the operator name? –  egreg Feb 8 at 18:13
    
It does know it for all the usual commands that start with \ . –  canaaerus Feb 8 at 18:14
3  
You're starting from a false premise. It's good to have a macro for constructs that are frequently used, such as the name of functions. –  egreg Feb 8 at 18:27

1 Answer 1

up vote 6 down vote accepted

You are starting from a false premise: it's good to have macros for frequently used constructs and math operators such as “sine” and “log” are no exception.

If an operator appears only a few times, then what's wrong in using

\operatorname{foo}

for those few cases? If you don't want to type so much, then

\newcommand{\op}[1]{\operatorname{#1}}

would allow simply typing

\op{foo}

that requires just three keystrokes more than your proposed syntax.

It's quite difficult to have a safe routine for scanning a name in the same way TeX does for control sequences. The scanning of control sequence names is built-in, while you should do it character by character, storing them as you go until finding something that's not a letter.

There's another catch: your proposed character ¡ will definitely not work if the document is compiled under

\usepackage[utf8]{inputenc}

because in that case it is not a single character, but two: its UTF-8 representation is 0xC2A1. You could use `, instead.

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

\ExplSyntaxOn
\tl_new:N \l__canaaerus_name_tl

\cs_new_protected:Npn \canaaerus_bq_mathop:
 {
  % clear the container
  \tl_clear:N \l__canaaerus_name_tl
  % start the recursion
  \canaaerus_absorb:
 }

\cs_new_protected:Npn \canaaerus_absorb:
 {
  \peek_catcode:NTF a
   {% if the next token is a letter absorb it
    \__canaaerus_absorb_next:n
   }
   {% otherwise produce the operator name
    \__canaaerus_deliver:
   }
 }

\cs_new_protected:Npn \__canaaerus_absorb_next:n #1
 {
  % add the next letter to the container
  \tl_put_right:Nn \l__canaaerus_name_tl { #1 }
  % restart the recursion
  \canaaerus_absorb:
 }

\cs_new_protected:Npn \__canaaerus_deliver:
 {
  % produce the operator name
  \operatorname{\l__canaaerus_name_tl}
 }

% define the active back quote
\group_begin:
\char_set_catcode_active:N `
\cs_gset_eq:NN ` \canaaerus_bq_mathop:
\group_end:
\ExplSyntaxOff

% make the backquote math active
\AtBeginDocument{\mathcode``=\string"8000 }

\begin{document}

$`cos(\alpha+\beta)-`sin x$

\end{document}

Highly inefficient, but working. Of course, syntax errors such as typing

`sinx

wouldn't be caught.

enter image description here

A different approach is to ease defining operators:

\documentclass{article}
\usepackage{xparse,amsmath}
\ExplSyntaxOn
\NewDocumentCommand{\DeclareMathOperators}{m}
 {
  \keys_set:nn { canaaerus/mathop } { #1 }
 }

\keys_define:nn { canaaerus/mathop }
 {
  unknown .code:n = \canaaerus_defop:n { #1 }
 }

\cs_new_protected:Npn \canaaerus_defop:n #1
 {
  \cs_if_exist:cTF { \l_keys_key_tl }
   {
    \msg_error:nnx { canaaerus/mathop } { exist } { \exp_not:c { \l_keys_key_tl } }
   }
   {
    \tl_if_empty:nTF { #1 }
     {
      \cs_new:cpx { \l_keys_key_tl } { \exp_not:N \operatorname { \l_keys_key_tl } }
     }
     {
      \cs_new:cpx { \l_keys_key_tl } { \exp_not:N \operatorname { #1 } }
     }
   }
 }
\msg_new:nnnn { canaaerus/mathop } { exist }
 {
  #1 already~defined
 }
 {
  The~command~#1 already~exists,~ignored
 }
\cs_generate_variant:Nn \msg_error:nnn { nnx }
\ExplSyntaxOff

\DeclareMathOperators{
  Tor,
  Hom,
  Span=span,
  %span, % if uncommented it would raise an error
}

\begin{document}
$\Tor\quad\Hom\quad\Span$
\end{document}
share|improve this answer
    
Can I use your code for defining a \DeclareMathOperators command as is, in a personal .sty or .cla file. I as k this question because it begins with \NewDocumentCommand – and a .sty or .cls file isn't really compiled. –  Bernard Feb 8 at 23:59
    
@Bernard You can put the code in a .sty file; just change \usepackage into \RequirePackage. Put there all from \RequirePackage to \ExplSyntaxOff –  egreg Feb 9 at 0:19
    
Is it possible to get the character used (backtick or ¡) from a macro (e.g. an argument to a package)? I tried to place \expandafters but it wouldn’t work... –  canaaerus Feb 9 at 14:29
2  
@canaaerus \expandafter is not abracadabra; what precisely do you want to do? –  egreg Feb 9 at 16:56
1  
@cfr Yes, XeLaTeX and LuaLaTeX first transform UTF-8 multibyte combinations into single characters. –  egreg Feb 9 at 20:24

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.