I sometimes want to compare FriCAS output with that what Mathematica
returns and also wanted to be able to cut&paste FriCAS expressions to
Mathematica without always having the need to change the syntax
manually. I therefore modified Format1D in such a way that it shows
Mathematica syntax.
Of course, that cannot be perfect, because OutputForm is an output
format and does not contain enough information. Nevertheless, the
attached file produces Mathematica expressions for many common cases.
Please try your favourite expression(s) and let me know where I should
adapt something.
Use as follows:
)compile fmtmma.spad
strmma x ==>
first(lines(format(format(x::OutputForm)$Formatter(FormatMathematica))))
dispmma x ==> display(x::OutputForm::Formatter(FormatMathematica))
strmma(sin(x)^(a+tan(x^(-1))))
dispmma(sin(x)^(a+tan(x^(-1))))
dispmma(sum(sin(k*x),k=1..n))
===============================
%%% (33) -> strmma(sin(x)^(a+tan(x^(-1))))
(33) "Sin[x]^(Tan[1/x]+a)"
Type: String
%%% (34) -> dispmma(sin(x)^(a+tan(x^(-1))))
Sin[x]^(Tan[1/x]+a)
Type: Void
%%% (35) -> dispmma(sum(sin(k*x),k=1..n))
[OUTPUTFORM = k = 1, SEXPRESSION = (= k 1)]
Sum[Sin[k*x], {k, 1, n}]
Type: Void
Ralf
--
You received this message because you are subscribed to the Google Groups "FriCAS -
computer algebra system" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to fricas-devel+unsubscr...@googlegroups.com.
To view this discussion visit
https://groups.google.com/d/msgid/fricas-devel/81040453-ba21-463d-aa48-7b871ee676ef%40hemmecke.org.
-------------------------------------------------------------------
---
--- FriCAS FormatMathematica
--- Copyright (C) 2025 Ralf Hemmecke <r...@hemmecke.org>
---
-------------------------------------------------------------------
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. Redistributions in binary form must reproduce the above
-- copyright notice, this list of conditions and the following
-- disclaimer in the documentation and/or other materials provided
-- with the distribution.
--
-- 3. Neither the name of the copyright holder nor the names of its
-- contributors may be used to endorse or promote products derived
-- from this software without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-- COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-- OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
-- This program first computes a data structure that represents the
-- documentation of all constructors and the documentation of their
-- signatures in raw (SExpression).
-- In the following pass, the ++ docstrings are embellished by
-- transforming (known) constructor names into links.
-- Finally, the data structure will be output into a collection of
-- .rst files that can be processed by sphinx.
-------------------------------------------------------------------
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{article}
\usepackage{literatedoc}
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\title{FormatMathematica---A formatter for Mathematica}
\author{Ralf Hemmecke}
\date{12-Mar-2025}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\maketitle
\begin{abstract}
The domain \spadtype{FormatMathematica} provides functionality to
transform an element of \spadtype{OutputForm} into a linear
(one-dimensional) form with the aim that it can be used directly via
cut\&paste as input to Mathematica.
\end{abstract}
\tableofcontents
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Overview}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
For an overview of the formatting framework in \SYSTEM{} look into the
\url{fmt.spad} document.
The domain \spadtype{FormatMathematica} try to output an expression in
a form that can be pasted into a Mathematica session. Since
\spadtype{OutputForm} does not necessarily provide all information to
reproduce the original expression this domain can only be considered
as an approximation to a true Mathematica expression. It will
certainly work in the most common cases, but are cases where the
output cannot be read properly by Mathematica.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{The Implementation of \spadtype{FormatMathematica}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
)abbrev domain FMTMMA FormatMathematica
++ \spadtype{FormatMMA} provides a coercion from \spadtype{OutputForm}
++ to a one-dimensional format such that the output can be pasted back
++ as input into a Mathematica session.
FormatMathematica: Exports == Implementation where
E ==> OutputForm
Z ==> Integer
N ==> NonNegativeInteger
S ==> String
LE ==> List E
BOX ==> OutputBox
LBOX ==> S -> BOX -- Label box for prologue and epilogue
HANDLER ==> (Z, LE) -> OutputBox -- (precedence, arguments) +-> resulting box
H ==> HANDLER
Exports ==> FormatterCategory
Implementation ==> add
Rep ==> Record(prolog: BOX, fmt: BOX, epilog: BOX)
ProEpi ==> Record(prolog: LBOX, epilog: LBOX)
import from Rep
rep x ==> (x@%) pretend Rep
per x ==> (x@Rep) pretend %
FE ==> formatExpression
MIN ==> minPrecedence()
MAX ==> maxPrecedence()
coerce(x: %): OutputForm == rep(x)::OutputForm
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
By default there is no prologue or epilogue for one-dimensional output.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
defaultPrologue(label: S): BOX == empty()
defaultEpilogue(label: S): BOX == empty()
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\spad{fricasEscapeString(s)} escapes all Mathamatica special characters.
These characters are: \verb|" \|. %"
We also escape these characters by the Mathematica escape character,
i.e., a backslash character.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
-- local function: fricasEscapeString
fricasEscapeString(s: S): S == -- local function
cc: CharacterClass := charClass "_"\"
p: Integer := position(cc, s, 1)
zero? p => s
str: S := ""
n: Integer := 1
while (p := position(cc, s, n)) > 0 repeat
str := concat(str, s(n..p-1))
n := p+1
esc := concat("\", s.p)
str := concat(str, esc)
concat(str, s(n..#s))
formatFunction(b: BOX, lb: List BOX): BOX ==
import from OutputFormTools
empty? lb => hconcat [b, parenthesize("[", "]", empty()$BOX)]
bx: BOX := first lb
for x in rest lb repeat bx := hconcat [bx, box ", ", x]
hconcat [b, parenthesize("[", "]", bx)]
function(op: S, p: Z, hh: H): H == prefix(op, p, bracket("[", "]", hh))
-- Take category default for formatInteger
formatFloat(s: S): BOX == box remove(char "__", s)
formatString(s: S): BOX ==
import from E
s = "true" => box "True"
s = "false" => box "False"
#s>1 and s.1 = char "_"" and s(#s) = char "_"" =>
parenthesize("_"", "_"", box fricasEscapeString s(2..#s-1))
box fricasEscapeString s
formatSymbol(s: S): BOX == box s
formatFunctionSymbol(s: S): BOX == box s
-- Functions from FormatterCategory
parenthesize(left: S, right: S, b: BOX): BOX ==
hconcat [box left, b, box right]
-- Replace x by y in expression z.
substitute(x: E, y: E, z: E): E ==
import from OutputFormTools
x = z => y
atom? z => z
args: List E := [substitute(x, y, a) for a in arguments z]
elt(substitute(x, y, operator z), args)
-- From e=(* a (CONCAT d x)) return x and empty() in case the form
-- does not have this structure.
getDExpression(e: E): E ==
import from OutputFormTools
atom? e => empty()
op: E := operator e
not is_symbol?(op, "*"::Symbol) => empty()
args: LE := arguments e
#args ~= 2 => empty()
op2: E := operator(args.2)
not is_symbol?(op2, "CONCAT"::Symbol) => empty()
args2: LE := arguments(args.2)
#args2 ~= 2 or not is_symbol?(first args2, "d"::Symbol) => empty()
args2.2
-- Check documentation in fmtcat.spad for the different cases.
integral(p: Z): H == (prec: Z, args: LE): BOX +->
-- We can assume #args=3.
bl: BOX := formatExpression(args.1, MIN) -- lower limit
bu: BOX := formatExpression(args.2, MIN) -- upper limit
empty? bu =>
lb: List BOX := [formatExpression(args.3, MIN)]
if not empty? bl then lb := concat(lb, bl)
return formatFunction(box "Integrate", lb)
--assert(not empty? bu)
b2: BOX := bu
x: E := getDExpression(args.3)
ba: BOX := formatExpression(args.3, MIN) -- default without substitution
if x ~= empty() then -- must replace in args.3
-- Here, the expression a=args.3 is of the form
-- (* a (CONCAT d x)). We substitute any x in a by
-- the upper limit and return this expression without
-- the (CONCAT d x) part.
bx: BOX := formatExpression(x, MIN)
-- remove (CONXAT d x) part
a: E := first arguments(args.3)$OutputFormTools
if empty? bl then -- must substitute
ba := formatExpression(substitute(x, args.2, a), MIN)
else -- no substitution necessary
-- limits are given by x=bl..bu
ba := formatExpression(a, MIN)
b2 := hconcat [box "{", bx, box ", ", bl, box ", ", bu, box "}"]
formatFunction(box "Integrate", [ba, b2])
-- local
operatorWithLimits(s: S, p: Z): H == (prec: Z, args: LE): BOX +->
-- We can assume #args>=2, but the first argument can be empty
bl: BOX := formatExpression(args.1, MIN) -- lower limit
ba: BOX := formatExpression(args.2, MIN) -- upper limit or arg
#args = 2 =>
empty? bl => formatFunction(box s, [ba])
formatFunction(box s, [ba, bl])
bu: BOX := ba -- upper limit
ba := formatExpression(args.3, MIN) -- arg (no parens needed)
-- Normally, lower limit looks like (= var val)
import from OutputFormTools
atom?(args.1) or not symbol?(op:=operator args.1) or
symbol(op) ~= "="::Symbol =>
b2: BOX := hconcat [box "{", bl, box ", ", bu, box "}"]
as: LE := arguments(args.1)
bv: BOX := formatExpression(as.1, MIN)
bl: BOX := formatExpression(as.2, MIN)
b2 := hconcat [box "{", bv, box ", ", bl, box ", ", bu, box "}"]
formatFunction(box s, [ba, b2])
sum(p: Z): H == operatorWithLimits("Sum", p)
product(p: Z): H == operatorWithLimits("Product", p)
theMap(prec: Z, args: LE): BOX ==
import from OutputFormTools
a: E := first args
s: S :=
atom? a and not string? a and not symbol? a => ";?;"
b: BOX := formatExpression(a, MIN) -- assume only one line!!!
first lines b -- strings are already run through texEscape
p1 := position(char ";", s)
p2 := position(char ";", s, p1+1)
parenthesize("theMap[", "]", box s(p1+1..p2-1))
overbar(p: Z, hh: H): H == (prec: Z, args: LE): BOX +->
formatFunction(box "OverBar", [hh(p, args)])
box(hh: H): H == (prec: Z, args: LE): BOX +->
formatFunction(box "Framed", [hh(prec, [args.1])])
-- \sqrt[n]{x}
nthRoot(p: Z, h1: H, h2: H): H == (prec: Z, args: LE): BOX +->
bx: BOX := h1(p, [args.1])
one?(# args) => formatFunction(box "Sqrt", [bx])
b2: BOX := formatFunction(box "Power", [h2(p, [args.2]),box "-1"])
formatFunction(box "Power", [bx, b2])
emptyArgument?(a: E): Boolean ==
import from OutputFormTools
atom? a => string? a and (string a = " " or string a = "")
is_symbol?(operator a, "NOTHING"::Symbol)
formatMaybeEmptyExpression(a: E): BOX ==
emptyArgument? a => box "_"_""
formatExpression(a, MIN)
scripts(p: Z): H == (prec: Z, args: LE): BOX +->
lb: List BOX := [formatMaybeEmptyExpression a for a in args]
empty? rest args => first lb
-- gives wrong expressionn if #lb>2
formatFunction(box "Subsuperscript", lb)
subscript(p: Z): H == (prec: Z, args: LE): BOX +->
b1: BOX := formatExpression(args.1, MIN)
b2: BOX := formatExpression(args.2, MIN)
formatFunction(box "Subscript", [b1, b2])
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The handler \spad{altsupersub} treats an expression that is generated by
\begin{verbcode}
supersub(a, [sub1, super1, sub2, super2, ...])
supersub(a, [l1, u1, l2, u2, ...])
\end{verbcode}
from \spadtype{OutputForm}. We basically turn it from its
representation in \spadtype{OutputForm} back into the above form.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
altsupersub(p: Z): H == (prec: Z, args: LE): BOX +->
lb: List BOX := [formatMaybeEmptyExpression a for a in args]
n: N := #args
one? n => first lb
if even? n then lb := concat(lb, box "_"_"")
formatFunction(box "Subsuperscript", lb)
-- we must treat the special format of a prime expression
prime(p: Z): H == (prec: Z, args: LE): BOX +->
b1: BOX := formatExpression(args.1, MIN)
n: Z := numberOfPrimes(args.2)
n < 0 => error "error in PRIME expression"
b2: BOX := box(convert(n)@String)
formatFunction(formatFunction(box "Derivative", [b2]), [b1])
power(p: Z, h1: H, h2: H): H == (prec: Z, args: LE): BOX +->
b1: BOX := h1(p+1, [args.1])
b2: BOX := h2(p+1, [args.2])
parenthesizeIf(p < prec, hconcat [b1, box "^", b2])
fraction(p: Z, h1: H, h2: H): H == (prec: Z, args: LE): BOX +->
b1: BOX := h1(p+1, [args.1])
b2: BOX := h2(p+1, [args.2])
parenthesizeIf(p < prec, hconcat [b1, box "/", b2])
slash(p: Z, h1: H, h2: H): H == fraction(p, h1, h2)
binomial(prec: Z, args: LE): BOX ==
b1: BOX := formatExpression(args.1, MIN)
b2: BOX := formatExpression(args.2, MIN)
formatFunction(box "Binomial", [b1, b2])
zag(prec: Z, args: LE): BOX ==
b1: BOX := formatExpression(args.1, MIN)
b2: BOX := formatExpression(args.2, MIN)
formatFunction(box "zag", [b1, b2])
vconcat(h: H): H == bracket("vconcat[", "]", nary(", ", MAX, FE MIN))
pile(h: H): H == bracket("pile[", "]", nary(", ", MAX, FE MIN))
matrix(left: S, right: S): H == (prec: Z, args: LE): BOX +->
entries: BOX := nary(", ", MAX, FE MIN)(prec, rest args)
parenthesize(left, right, entries)
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Now all function are defined and we can fill the \spad{oh}
data structure.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
setOperatorHandlers!(oh: OperatorHandlers H): OperatorHandlers H ==
NARY ==> -1 -- means n-ary.
PAREN p ==> bracket("(", ")", FE p)
PAREN2(p1, p2) ==> bracket("(", ")", infix(", ", MAX, FE MIN, FE MIN))
FUNCTION s ==> function(s, MAX, FE MIN)
o(n, op, hdl) ==> setHandler!(oh, n, op, hdl)
o(0, "NOTHING", nothing())
o(0, "%pi", formatConstant "Pi")
o(0, "%e", formatConstant "E")
o(0, "%i", formatConstant "I")
o(0, "true", formatConstant "True")
o(0, "false", formatConstant "False")
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Note that we would need more effort to rediscover \verb|%plusInfinity|
and \verb|%minusInfinity| from the \spadtype{OutputForm}
representation.
\begin{verbcode}
(82) -> e %plusInfinity
[OUTPUTFORM = + infinity, SEXPRESSION = (+ (NOTHING) infinity)]
(83) -> e %minusInfinity
[OUTPUTFORM = - infinity, SEXPRESSION = (- infinity)]
(84) -> e %Infinity
[OUTPUTFORM = %Infinity, SEXPRESSION = %Infinity]
\end{verbcode}
Here we (wrongly) return \verb|+%Infinity| and \verb|-%Infinity| for
\verb|%plusInfinity| and \verb|%minusInfinity|.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif
o(0, "%Infinity", formatConstant "Infinity")
o(0, "infinity", formatConstant "Infinity") -- for %minusInfinity
o(0, "...", formatConstant "...")
o(1, "cos", FUNCTION "Cos")
o(1, "cot", FUNCTION "Cot")
o(1, "csc", FUNCTION "Csc")
o(1, "log", FUNCTION "Log")
o(1, "sec", FUNCTION "Sec")
o(1, "sin", FUNCTION "Sin")
o(1, "tan", FUNCTION "Tan")
o(1, "cosh", FUNCTION "Cosh")
o(1, "coth", FUNCTION "Coth")
o(1, "csch", FUNCTION "Csch")
o(1, "sech", FUNCTION "Sech")
o(1, "sinh", FUNCTION "Sinh")
o(1, "tanh", FUNCTION "Tanh")
o(1, "acos", FUNCTION "ArcCos")
o(1, "asin", FUNCTION "ArcSin")
o(1, "atan", FUNCTION "ArcTan")
o(1, "erf", FUNCTION "Erf")
o(1, "Gamma", FUNCTION "Gamma")
o(1, "-", prefix("-", 710, FE 715))
o(1, "not", FUNCTION "Not")
o(1, "QUOTE", FUNCTION "HoldFormComplete")
o(1, "OVERBAR", overbar(MAX, FE MIN))
o(1, "BOX", box FE MIN)
o(1, "Aleph", FUNCTION "\[Aleph]")
o(1, "BRACE", bracket("{", "}", FE MIN)) -- set as list
o(1, "BRACKET", bracket("{", "}", FE MIN)) -- Mathematica lists
o(1, "PAREN", bracket("(", ")", FE MIN))
o(1, "ROOT", FUNCTION "Sqrt")
o(1, "SEGMENT", bracket("", " .. ", FE 990))
o(1, "STRING", bracket("_"", "_"", FE MIN))
o(2, "rem", function("Mod", MAX, nary(", ",MAX,FE MIN)))
o(2, "quo", function("Quotient", MAX, nary(", ",MAX,FE MIN)))
o(2, "exquo", function("Quotient", MAX, nary(", ",MAX,FE MIN)))
o(2, "^", power(950, FE 960, FE 960))
o(2, "/", fraction(910, FE 910, FE 910))
o(2, "OVER", fraction(910, FE 910, FE 910))
o(2, "SLASH", slash(910, FE 910, FE 910))
o(2, "ZAG", zag)
o(2, "BINOMIAL", binomial)
o(2, "PRIME", prime MAX)
o(2, "ROOT", nthRoot(970, FE MIN, FE MIN))
o(2, "SUB", subscript 950)
o(2, "SEGMENT", infix(" .. ", 100, FE 100, FE 100))
o(2, "TENSOR", prefix("tensor", MAX, PAREN2(MIN, MIN)))
o(2, "EQUATNUM", prefix("\EQUATNUM", MAX, PAREN2(MIN, MIN)))
o(2, "OVERLABEL", prefix("\OVERLABEL", MAX, PAREN2(MIN, MIN)))
o(2, "==", nary("==", 400, FE 401))
o(2, "=", nary("==", 400, FE 400))
o(2, "~=", nary("!= ", 400, FE 400))
o(2, "<", nary("<", 400, FE 400))
o(2, ">", nary(">", 400, FE 400))
o(2, "<=", nary("<=", 400, FE 400))
o(2, ">=", nary(">=", 400, FE 400))
o(2, "and", nary(" && ", 300, FE 300))
o(2, "or", nary(" || ", 200, FE 200))
o(2, "LET", nary("=", 125, FE 125))
o(2, "->", nary("->", 1001, FE 1001))
o(2, "~>", nary("->", 100, FE 100))
o(2, "+->", function( "FUNCTION", MAX, nary(", ",MAX,FE MIN)))
o(2, "|", nary(" | ", 100, FE 100))
o(2, "SIGMA", sum 750)
o(2, "PI", product 750)
o(3, "SIGMA2", sum 750)
o(3, "PI2", product 750)
o(3, "INTSIGN", integral 700)
o(NARY, "+", naryPlus("+", "-", 700, FE 700))
-- Does n-ary minus ever appear in OutputForm???
o(NARY, "-", naryPlus("+", "-", 700, FE 700))
o(NARY, "*", nary("*", 800, FE 800))
o(NARY, "AGGLST", nary(", ", MAX, FE MIN))
o(NARY, "AGGSET", nary("; ", MAX, FE MIN))
o(NARY, "CONCAT", nary("", MAX, FE MIN))
o(NARY, "CONCATB", nary(" ", MAX, FE MIN))
o(NARY, "ALTSUPERSUB", altsupersub 900)
o(NARY, "SUPERSUB", scripts 900)
o(NARY, "SC", pile FE MIN) -- pile notation
o(NARY, "VCONCAT", vconcat FE MIN)
o(NARY, "ROW", bracket("{", "}", nary(", ", MAX, FE MIN)))
o(NARY, "MATRIX", matrix("{", "}"))
o(NARY, "theMap", theMap) -- one or two arguments
return oh
-- local variable declarations and definitions
operatorData: OperatorHandlers(H) := setOperatorHandlers! new()
operatorHandlers(): OperatorHandlers(HANDLER) == operatorData
)if LiterateDoc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
)endif