[HN Gopher] Typst's Math Mode Problem
       ___________________________________________________________________
        
       Typst's Math Mode Problem
        
       Author : marcianx
       Score  : 103 points
       Date   : 2025-10-24 18:12 UTC (6 days ago)
        
 (HTM) web link (laurmaedje.github.io)
 (TXT) w3m dump (laurmaedje.github.io)
        
       | TimorousBestie wrote:
       | Having run into this bug/syntax ambiguity in my writing a lot, I
       | don't find it's much of a bother. The typst engine runs fast
       | enough that most of the time I can run a synced preview window,
       | which makes this particular foible easy to catch.
        
       | jeremyscanvic wrote:
       | I've encountered this several times and even though I found it
       | frustrating it didn't occur to me it could be something that
       | could/should be fixed. You're always going to have some quirks if
       | you want a syntax without too much parentheses right?
        
       | MayeulC wrote:
       | In LaTeX that would be close to option 2:
       | e^{|x|}         f_{i(x)}
       | 
       | Except with {} for grouping, which I think is a good thing, as {}
       | are never rendered, unlike parenthesis.
       | 
       | I haven't used Typst much, so I am a bit wary of typesetting
       | engines that are "too smart": It can be problematic when
       | introducing new notations, which is quite common.
        
       | fn-mote wrote:
       | The post should lead with the proposed conclusion (revert and
       | require explicit grouping) so that the reader can think about the
       | arguments knowing the conclusion.
        
       | weinzierl wrote:
       | I had my gripes with LaTeX but the backslash in front of every
       | macro was never one of them. I think it helps not only machine
       | parsing but very much my human visual parsing.
       | 
       | BTW one related trap in LaTeX is if a macro without parameters
       | removes the trailing space from the output. The article mentions
       | this in passing but does not say what Typst's solution is. Do
       | Typst functions always require parentheses?
       | 
       | I'm also confused about the following syntax and especially where
       | the function ends:                   table.header([A], [B]) //
       | This one is clear              table.header()[A] // Makes sense,
       | [A] turns magically into last param
       | table.header()[A][B] // Slightly confusing, why would [B] also
       | belong to the function? But OK.              table.header()[A]
       | [B] // Totally confusing, why is this an error now?
       | 
       | For the last case: If it is a parameter list a space should not
       | matter, if it is not [B] should not be part of the function and
       | treated as unrelated.
        
         | laurmaedje wrote:
         | While not really related to the math topic, let me answer this:
         | 
         | - You can add an arbitrary number of trailing `[..]` blocks and
         | they are just trailing arguments. So 2 & 3 are really the same.
         | 
         | - 3 & 4 are different because argument lists may _never_ have a
         | space before them in Typst. you can also not write `calc.min
         | (1, 2)`
         | 
         | The reason why the space may not be added is that you can write
         | #for x in range(5) [             Value is #x         ]
         | 
         | And `range(5) [..]` therefore needs to be different from
         | `range(5)[..]`. This aligns with normal formatting conventions
         | and I haven't seen this become a problem in practice.
        
           | weinzierl wrote:
           | Seeing it this way it makes sense. Thanks!
        
         | xico wrote:
         | Plus you can always `\catcode\[?]=0` if you really hate
         | backslashes :-D
        
       | nightskyblue wrote:
       | When I found out that option B was already merged [1] I got very
       | excited because the current behavior is still very unintuitive to
       | me and one of the few areas where I prefer the behavior from
       | Latex. Unfortunately, the changes were reverted shortly after
       | because they discovered deeper issues with the new old design
       | [2]. As far as I can see, there hasn't been any further progress
       | on this, sadly.
       | 
       | [1] https://github.com/typst/typst/pull/6442
       | 
       | [2] https://github.com/typst/typst/pull/7084
        
         | fweimer wrote:
         | I find
         | https://github.com/typst/typst/pull/7072#issuecomment-338580...
         | more enlightening about what's going on. Specifically the
         | difference between these three:                  1/2(x + y)
         | 1/x(x + y)        1/2^x(x + y)
         | 
         | With a programming language background, that's just odd to
         | reconcile. If 1/2 is treated as a rational integer literal,
         | it's possible to explain the difference between the first two.
         | (And apparently this difference is wildly expected, uncommon as
         | fractions as literals are in programming languages.) But then
         | the last one should turn into (1/2)x(x+y) because the
         | exponentiation should not slip inside the literal. (I expect
         | the different outcome in the comment is not the result of an
         | algebraic simplification in his case. I really wish they had
         | used 2/3 as the fraction to clarify this.)
         | 
         | It seems that TeX users struggled with this at one point, too.
         | That's why LaTeX users generally write $\frac{a}{b}$ instead of
         | $a \over x$. Copious use of braces not rendered in the output
         | certainly avoids precedence issues.
        
           | MayeulC wrote:
           | It's also a cultural thing I suppose, as I would personally
           | understand all these expressions having just one as the
           | numerator and the rest below.
           | 
           | It may be related to the fact that "mixed numbers" were never
           | part of my curriculum (Wikipedia1 says they are more common
           | in non-metric regions). Or it may be just me. In any case, I
           | find this notation ambiguous, so I would not expect a
           | compiler to resolve it correctly.
           | 
           | Edit: also, I would rather write (x + y)/2 if I wanted half
           | the sum, that seems much more logical to me than moving non-
           | integer factors around.
           | 
           | 1 https://en.wikipedia.org/wiki/Fraction#Mixed_numbers
        
             | fweimer wrote:
             | > Edit: also, I would rather write (x + y)/2 if I wanted
             | half the sum, that seems much more logical to me than
             | moving non-integer factors around.
             | 
             | Based on what I recall, there's a bit of an aversion
             | towards writing / or / for division (or explicitly written
             | multiplication). And $\frac{1}{2}(x+y)$ is more readable in
             | inline text than $\frac{x+y}{2}$.
        
               | MayeulC wrote:
               | I agree, though I wish you had specified in what context
               | that aversion was.
               | 
               | To give a specific example, I can cite units in the
               | metric system, often written as kg.s-2.J-1 instead of the
               | more ambiguous kg/s2/J; which could technically be read
               | as kg/(s2/J), giving kg.J.s-1.
        
         | davorak wrote:
         | The newest pull request is:
         | 
         | https://github.com/typst/typst/pull/7137
         | 
         | from what I can tell. The commits look two days old so work
         | looks on going.
         | 
         | I do not understand the current set of preferences laid out in:
         | 
         | https://github.com/typst/typst/pull/7072#issuecomment-338580...
         | 
         | I do not understand 8, 9 'my preference' column and why they
         | would make the similar syntax render differently.
        
           | laurmaedje wrote:
           | (Author of the post and issue comment here.)
           | 
           | The preferences there were honestly rather ad-hoc w.r.t to
           | the pull request and the approach the pull request took. And
           | (as the author laid out), the PR was a rather ad-hoc solution
           | for a problem we discovered literally one night before Typst
           | 0.14 was supposed to be released.
           | 
           | The design thoughts there were a bit half-baked, which is why
           | we've closed the PR and reverted the original change, to get
           | more time to properly reconsider things.
           | 
           | The math syntax has seen little change since Typst's initial
           | release (except for the infamous precedence change in 0.3
           | that triggered all this) and just has some quirks that
           | haven't been properly ironed out yet. However, it will remain
           | a focus now and we want to give it a proper cleanup.
        
       | andrepd wrote:
       | I really don't see the problem with the current notation. I find
       | that is very simple and intuitive: function calls bind tightly,
       | use a space to change that.
       | 
       | f_i(x) vs f_i (x)
       | 
       | 1/x(a+b) vs 1/x (a+b)
       | 
       | ab vs a b
       | 
       | So simple. Being too "smart" invariably leads to more headaches
       | and confusion than just having a simple, consistent rule.
        
         | zygentoma wrote:
         | Exactly this!
         | 
         | It is just plain simpler than the original TeX/LaTeX notation.
        
         | fwlr wrote:
         | From quickly messing around in the playground, it seems (in
         | math mode) Typst treats multiple spaces identical to single
         | spaces. A simple, consistent, flexible, and probably-not-
         | majorly-breaking-old-documents rule would be "anything with no
         | spaces has higher precedence / tighter binding than anything
         | with one space, anything with one space has higher precedence /
         | tighter binding than anything with two spaces", etc, and then -
         | only within each spaces category - you apply one of the
         | precedence rulesets described in the article. Any confusion or
         | surprise can be solved intuitively and without thought by
         | mashing spacebar.
        
           | tonyarkles wrote:
           | I agree with you conceptually, and am also laughing a bit
           | thinking about how many people get angry about significant
           | whitespace in Python and how much deeper down that rabbit
           | hole "operator precedence changes based on whitespace" this
           | proposal is :D
        
       | IshKebab wrote:
       | They missed another option: require brackets where it would
       | otherwise be ambiguous.
        
       | runarberg wrote:
       | In mathup[1] I handle this by allowing authors to strategically
       | place space around groups they want to operate on:
       | e^ x-1  <- "e with x minus one as superscript"         e^x - 1
       | <- "e with x as superscript minus one. Same as e^x-1"         f_
       | i(x)  <- "f with i of x as subscript"         f_i (x) <- "f with
       | i as subscript of x. Same as f_i(x)"
       | 
       | I also implemented invisible operators (plus, times, function
       | application, and separator) with special operators (`.+`, `.*`,
       | `.$`, and `.,` respectively) so authors can be explicit about
       | their intentions (and output more accessible expressions)
       | f_i .$ (x)         a / b.*(1 - x)         sum_ X_ i.,j
       | 
       | 1: https://mathup.xyz/
        
       | vitriol83 wrote:
       | are there any tools to convert large latex documents to typst ?
       | it looks a huge improvement, but the migration path is the only
       | thing that's stopping me.
        
         | laurmaedje wrote:
         | Pandoc [1] can convert LaTeX to Typst.
         | 
         | [1]: https://pandoc.org/
        
       | sureglymop wrote:
       | I like typst but in all honesty I was a bit disappointed when I
       | saw that they didn't have a backwards compatible math mode.
       | Looking at all the shortcomings of latex, I wouldn't say the math
       | notation is part of it.
       | 
       | And since probably many people are very familiar with it, I would
       | have liked for them to just keep that part.
        
       | ajkjk wrote:
       | It feels absurd to have this occur in the parser, as if you can
       | somehow account for all the cases via guessing what people I
       | mean. You absolutely _must_ have a grouping operation like {} at
       | least available as a fallback.
       | 
       | I feel like this is a lesson people keep learning over and over
       | across programming languages: don't let your syntax try to infer
       | the intended meaning of what was typed, just do something simple
       | and predictable.
       | 
       | So (b) seems like the only sane choice, but having the grouping
       | operation being e^(abs(x)) is also crazy. You need something like
       | TeX's e^{abs(x)}.
       | 
       | Personally I think the "best" workaround for this is to decouple
       | the text representation and the representation the editing
       | happens in. Allow people to type e^abs(x) and then the _editor_
       | translates that into e^{abs(x)} while letting you edit it as an
       | exponential, but if you 're working on the underlying text file
       | then you have to write e^{abs(x)}. For that matters, you can just
       | have the editor represent it as a literal superscript.
       | 
       | (My hunch is that this is generally much-needed across languages:
       | let the editor do some of the parsing work. I think there's much
       | to be gained by separating the two, because you can keep the
       | parser of the actual language simple while still getting all your
       | editing-efficiency improvements out of the editor).
        
         | trueismywork wrote:
         | I complained about this before and people dismissed me as an
         | old timer. I did doubt myself as well to be honest. Its
         | bittersweet to be correct.
        
           | lou1306 wrote:
           | I hate recurse to authority, but after a markup slash
           | programming language has been written by Don Knuth and a
           | macro system for it has been developed by Leslie Lamport,
           | maybe one should take some notes so as to why things were
           | done in a certain way?
        
             | cruegge wrote:
             | They're not infailable, though. For example, TeX's
             | primitive for fractions is actually {a \over b}, LaTeX's
             | \frac is a macro on top of that. The consequence is that
             | while typesetting a formula, the engine does not know the
             | current text size, since an \over further down the line may
             | put the entire thing into a numerator. Dealing with this
             | can be quite a pain when writing math macros.
        
             | TimorousBestie wrote:
             | I actually think Typst should ignore the design of TeX and
             | LaTeX more--and especially the well-meaning advice of LaTeX
             | veterans who have only ever known one way of typesetting.
             | 
             | The situation reminds me of how Julia's evolution was
             | guided in some aspects by some opinionated and vocal
             | {Python, R, MATLAB} developers who never had any intention
             | of transitioning to Julia, whether or not their advice was
             | implemented.
        
         | runarberg wrote:
         | I am the author of a (somewhat) competing parser called
         | mathup[1] which has a similar syntax. I based mine heavily off
         | of AsciiMath which has {: group :} as a fallback grouping
         | operator. I kept it, but if I would have done it over I would
         | have replaced it with { group } and used {: group :} for curly
         | brackets.
         | 
         | I had a similar dilemma before I released 1.0.0 last spring,
         | and decided against special cases like these. In Mathup binary
         | operators (^, _, and /) always operate on exactly one group
         | after the operator, regardless of (what I believe is) the
         | author's intention. So 1/2(x, y) is the same as 1/x(i, j) is
         | the same as 1/f(x, y). I only have a couple of exceptions
         | regarding spacing on trig functions, and (what I believe is)
         | the differential operator. But if you want an implicit group to
         | e.g. under a fraction, in a superscript, you must either denote
         | that with spaces e^ x-1, or with parens e(x-1) [I courteously
         | drop the parens from the output in these troubled expressions].
         | 
         | 1: https://mathup.xyz
        
         | jraph wrote:
         | > Personally I think the "best" workaround for this is to
         | decouple the text representation and the representation the
         | editing happens in. Allow people to type e^abs(x) and then the
         | editor translates that into e^{abs(x)} while letting you edit
         | it as an exponential, but if you're working on the underlying
         | text file then you have to write e^{abs(x)}. For that matters,
         | you can just have the editor represent it as a literal
         | superscript.
         | 
         | I'm pretty sure that's how LyX does it, possibly others as
         | well.
        
         | abdullahkhalids wrote:
         | Typst has made some basic choices, which as someone who typsets
         | a lot of math, makes it a no go.
         | 
         | - The use of space character to also act as the escape
         | character (latex use backslash) [1]. Not only does it cause
         | confusion, I have to now escape everything $F=ma$ become $ F =
         | m a $ in typst. Complex math equations will be complex no
         | matter what - why make simple equations harder to type to make
         | it slightly easier to type complex ones.
         | 
         | - The lack of these grouping brackets (latex uses curly
         | parenthesis).
         | 
         | What I want from my typesetting language is "typsetting
         | completeness". While there might be sane defaults, I want to be
         | able to control every decision made by the typesetter by
         | escaping and grouping things as needed. If the language doesn't
         | have these features, by definition, it is not complete.
         | 
         | [1] Latex also has to use space to act as ending delimiters.
         | $\alpha x$ is correct and $\alpha\beta$ is correct, but
         | $\alphax$ is not. But the solution to this is to allow $ax$
         | which some flavors of tex do.
        
           | runarberg wrote:
           | As an author of a different math typesetting tool (mathup) I
           | explicitly made the choice of making simple expressions
           | simple to type at the expense of making complex equations
           | less intuitive. But I still have the same problem as OP,
           | where simple expressions break because the intuitive behavior
           | is the opposite of what my parser does.
           | 
           | AsciiMath (what my tool was inspired by) tries to be smart
           | about this by parsing a/f(x) differently from a/x(f) and it
           | looks like typst is making the same choose. I on the other
           | hand opted to rather stay consistent. My reasoning is that
           | the tool is fast enough, and I rarely (actually never) type
           | my math expressions outside of an interactive experience
           | where I can't view the rendered result as I type, so I can
           | spot my mistakes immediately (usually fixed by adding a
           | space, or surrounding something with parens).
        
           | TimorousBestie wrote:
           | > What I want from my typesetting language is "typsetting
           | completeness". While there might be sane defaults, I want to
           | be able to control every decision made by the typesetter by
           | escaping and grouping things as needed. If the language
           | doesn't have these features, by definition, it is not
           | complete.
           | 
           | Then LaTeX is not complete. Macros don't have to respect the
           | grouping provided by curly braces in math mode, therefore you
           | only have the illusion of control. Nobody in practice
           | actually inspects the full package dependency chain needed to
           | typeset a nontrivial document.
           | 
           | Here's a proof of concept:
           | https://tex.stackexchange.com/questions/748416/how-can-i-
           | aut...
        
             | abdullahkhalids wrote:
             | Yes it is not. I think a replacement for latex is needed,
             | but it needs to make better design choices than Typst.
             | 
             | That said, Typst has many good things, like easy to write
             | methods, which this new language should adopt.
        
           | vitorsr wrote:
           | > Typst has made some basic choices, which as someone who
           | typsets a lot of math, makes it a no go.
           | 
           | For me, breaking from not just a 40-year-old history of
           | mathematical typesetting but also from the _American
           | Mathematical Society_ recommendations is the dagger. Plus
           | doubling work if you want to reuse what you wrote to render
           | MathJax or KaTeX.
           | 
           | > $\alpha x$ is correct and $\alpha\beta$ is correct, but
           | $\alphax$ is not.
           | 
           | Like you said, braces can be used so all of the following are
           | valid: ${\alpha}x$, $\alpha{x}$ or the odd $\alpha{}x$.
        
       | Voklen wrote:
       | I love well-reasoned, thorough articles like this with all the
       | tradeoffs considered. It makes me confident in Typst's future.
        
       | eviks wrote:
       | >pi(1 + 2) is a function call or just pi multiplied by three.
       | 
       | another case for using proper notation p with some
       | autosubstitution rules so that you can resolve the ambiguity
       | immediately while typing (if pi is converted into p you backspace
       | and let it stay pi as a function)
       | 
       | But #functions also seems like a good option for readability
        
         | runarberg wrote:
         | MathML recommends using the invisible operators for invisible
         | times or function application (&InvisibleIimes; [U+2062] and
         | &af; [U+2061] respectively) to differentiate the two.
        
           | eviks wrote:
           | Unfortunately, they're... invisible. Though they can still be
           | highlighted in an editor, so also helpful
        
             | runarberg wrote:
             | You notate the operation with * and $ (in mathup I use .*
             | and .$ to make the operator invisible). Literal p is used
             | both as a constant and as a function identifier depending
             | on context so p(1 + n) can either be e.g. the (n+1)th prime
             | or pi times one plus n. It is usually clear from context
             | which one the author meant but if it is a problem explicit
             | notation could help for sure.
             | 
             | I have also heard that the invisible operators help with
             | accessibility. I haven't tested this on my screen reader,
             | but I suppose <mi>p</mi><mo>&af;</mo><!-->...<--> would
             | read something like _"Pi of ..."_ whereas
             | <mi>p</mi><mo>&InvisibleTimes;</mo><!-->...<--> would read
             | something like _"Pi times ..."_ all the while
             | <mi>p</mi><mrow><mo>(</mo> would just read _"Pi [open
             | parenthesis] ..."_.
        
               | eviks wrote:
               | Good point about primes, not enough symbols for
               | uniqueness, so just p isn't enough! Though using two
               | symbols ( .* ) in place of nothing is too dirty, better
               | use an invisible and color highlight the spacing between
               | p and ( to indicate to the plain text reader the
               | difference.
               | 
               | Win screenreaders understands 2. _3 (pronounced two
               | three) vs 23 (twenty three), though it doesn 't pronounce
               | the operator, neither in a._2 vs a2 (though pronounced
               | differently). But this could be fixable, so also good
               | point about accessibility
        
       | Ericson2314 wrote:
       | IMO a math mode that was less syntactic but more semantic would
       | solve all these issues                  exp(e, abs(x))
       | 
       | Boom; fixed. Can't say I really mind the verbosity either.
        
       | __mharrison__ wrote:
       | I'm not a big math mode user (but I use typst a lot).
       | 
       | Latex equation compatibility seems like a blocker for many. Maybe
       | they should have a library that allows one to drop in latex
       | formulas?
        
         | jeremyscanvic wrote:
         | Seems to be what those guys are up to:
         | https://typst.app/universe/package/mitex/
        
       | sconeman wrote:
       | For those not familiar with the Typst library, it feels important
       | to mention there is an `attach` function which gives much more
       | explicit control of sub/superscript type-stetting. I'm surprised
       | the blog didn't mention this at all as an option.
       | 
       | Docs: https://typst.app/docs/reference/math/attach/
        
       ___________________________________________________________________
       (page generated 2025-10-30 23:01 UTC)