PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Meta Programming \value Problem



Tux
25-07-2011, 20:19
Hallo Forum,

ich tüftel gerade an einem command, das "Methodenaufrufe" deligieren soll. Dabei habe ich ein Problem bei dem "Return" eines counter \values und komme nicht weiter. Es wäre super, wenn mir jemand von euch helfen könnte!

EDIT: Ich setze in dem Beispiel auf Currying (http://de.wikipedia.org/wiki/Currying). Hier (http://www.tex.ac.uk/cgi-bin/texfaq2html?label=moren9) ist das auch im LaTeX Universum erklärt.

Hier ist ein Minimalbeispiel:



\documentclass{article}

\newcounter{test}
\newcommand{\test}[1][]{\csname testA#1\endcsname}
\def\testAadd#1{\addtocounter{test}{#1}\test}
\def\testAprint{\the\value{test}\test}

\def\testAvalue{\value{test}} % hier liegt irgendwo das Problem

\begin{document}

\test[add]{1}[print][add]{2}[print][print][add]{4}[print]

\newcounter{tmp}
\setcounter{tmp}{\test[value]} % Zeile auskommentieren und es klappt
\end{document}


Wird die oben gekennzeichnete Zeile auskommentiert, kompiliert der Code und das Dokument wird erzeugt:


1337

Tut man das nicht, ist die Fehlermeldung:


Latex Error: ./MB.tex:15 Missing number, treated as zero.

Der (hoffentlich) relevante Ausschnitt des (sehr kurzen) .log-Files:



\c@tmp=\count88

./MB.tex:15: Missing number, treated as zero.
<to be read again>
\let
l.15 \setcounter{tmp}{\test[value]}

A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)


Wird die fehlerhafte ("auszukommentierende") Zeile oben durch diese zwei Zeilen ersetzt, läuft das Programm:



\setcounter{tmp}{\value{test}}
\the\value{tmp}


Das ist für mich aber keine Lösung des Problems, da ich gerne die ursprüngliche Notation beibehalten würde.

Hat irgendjemand einen Lösungsvorschlag oder eine Idee, wo ich weiterforschen könnte? Ich bin für jede Hilfe dankbar! :)

Tux
26-07-2011, 13:51
Ich habe noch ein bisschen Zeit in das Problem investiert und es gelöst. Danke zunächst einmal an diejenigen, die sich vielleicht auch den Kopf zerbrochen haben ;). Falls nochmal jemand die gleiche Frage haben sollte, hier meine Lösung:



\documentclass{article}
\makeatletter

\def\test[#1]{\csname test@#1\endcsname} % call "methods"
\newcounter{test}

% "method" definitions
\def\test@chain{\@ifnextchar[{\test}{}} % chaining through currying
\def\test@add#1{\addtocounter{test}{\numexpr#1}\te st@chain}
\def\test@print{\the\value{test}\test@chain}
\def\test@value{\value{test}}

\makeatother
\begin{document}
\setcounter{test}{0}
\test[add]{1}[print][add]{2*\test[value]}[print][print][add]{4}[print]
% => 1337

\setcounter{test}{0}
\test[add]{1}
\test[print] % => 1
\test[add]{2*\test[value]}[print] % => 3
\test[print][add]{4} % => 3
\test[print] % => 7
\end{document}


Das Problem scheint zu sein, dass in



\newcommand{\test}[1][]{\csname testA#1\endcsname}


nicht wie intuitiv zu erwarten wäre,



\csname testA#1\endcsname


als command an letzter Stelle des Blocks stehen bleibt. Deshalb wird in



\def\testAvalue{\value{test}}


kein "\value" zurückgegeben, das an "\addtocounter" weitergereicht werden kann. Deshalb die Veränderung des "\newcommand" zu einem "\def" und die Einführung einer "@chain" "Methode", die abprüft, ob ein weiterer "Methodenaufruft" durch ein "[" angekündigt wird.

Vielleicht ist das ja in Zukunft nochmal für jemanden von Belang.

u_fischer
26-07-2011, 14:50
Dein wesentliches Problem ist, dass Befehle mit optionalen Argument normalerweise nicht expandierbar sind, und daher nicht in einem \setcounter-Befehl funktionieren:


\documentclass{article}
\begin{document}
\newcommand{\test}[1][]{1}
%\setcounter{section}{\test} %Fehler
\renewcommand\test{50}
\setcounter{section}{\test}
\section{A}
\renewcommand\test[1]{#1}
\setcounter{section}{\test{100}}
\section{B}
\end{document}



Zum zweiten hast du evtl. \value nicht ganz verstanden. Das gibt nicht, wie viele glauben einen Wert zurück, sondern einen Zähler: \def\value#1{\csname c@#1\endcsname}

An bestimmten Orten kann man \value so benutzen, als wäre es einen Wert: Dort wo es auch erlaubt ist, einen Zähler zu benutzen. Aber wenn es alleine in der Gegend rumsteht, bekommt man einen "missing number"-Fehler:


\documentclass{article}

\newcounter{test}
\setcounter{test}{2}
\begin{document}

\value{section}=2*\value{test}

%\value{test} %fehler

\value{test}=1 %ok

\number\value{test}

\end{document}