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).
abdullahkhalids 12 hours ago [-]
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 $αx$ which some flavors of tex do.
vitorsr 9 hours ago [-]
> 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$.
runarberg 11 hours ago [-]
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 10 hours ago [-]
> 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.
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.
trueismywork 14 hours ago [-]
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 13 hours ago [-]
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 10 hours ago [-]
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 10 hours ago [-]
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.
ajkjk 5 hours ago [-]
agree, I'm fine with Typst throwing out the old ways and doing the new ones... just, do your research; do it right
jraph 12 hours ago [-]
> 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.
runarberg 14 hours ago [-]
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].
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 15 hours ago [-]
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 14 hours ago [-]
Seeing it this way it makes sense. Thanks!
xico 14 hours ago [-]
Plus you can always `\catcode\∘=0` if you really hate backslashes :-D
nightskyblue 16 hours ago [-]
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.
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 (½)ˣ(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 14 hours ago [-]
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 (Wikipedia¹ 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.
> 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 12 hours ago [-]
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⁻².J⁻¹ instead of the more ambiguous kg/s²/J; which could technically be read as kg/(s²/J), giving kg.J.s⁻¹.
I do not understand 8, 9 'my preference' column and why they would make the similar syntax render differently.
laurmaedje 15 hours ago [-]
(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.
2 hours ago [-]
MayeulC 17 hours ago [-]
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.
sconeman 13 hours ago [-]
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.
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 17 hours ago [-]
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?
Voklen 14 hours ago [-]
I love well-reasoned, thorough articles like this with all the tradeoffs considered. It makes me confident in Typst’s future.
__mharrison__ 14 hours ago [-]
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?
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.
eviks 14 hours ago [-]
>pi(1 + 2) is a function call or just pi multiplied by three.
another case for using proper notation π with some autosubstitution rules so that you can resolve the ambiguity immediately while typing (if pi is converted into π you backspace and let it stay pi as a function)
But #functions also seems like a good option for readability
runarberg 11 hours ago [-]
MathML recommends using the invisible operators for invisible times or function application (&InvisibleIimes; [U+2062] and ⁡ [U+2061] respectively) to differentiate the two.
eviks 11 hours ago [-]
Unfortunately, they're... invisible. Though they can still be highlighted in an editor, so also helpful
runarberg 10 hours ago [-]
You notate the operation with * and $ (in mathup I use .* and .$ to make the operator invisible). Literal π is used both as a constant and as a function identifier depending on context so π(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>π</mi><mo>⁡</mo><!-->...<--> would read something like “Pi of ...” whereas <mi>π</mi><mo>⁢</mo><!-->...<--> would read something like “Pi times ...” all the while <mi>π</mi><mrow><mo>(</mo> would just read “Pi [open parenthesis] ...”.
eviks 9 hours ago [-]
Good point about primes, not enough symbols for uniqueness, so just π isn't enough! Though using two symbols ( .* ) in place of nothing is too dirty, better use an invisible and color highlight the spacing between π 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
sureglymop 14 hours ago [-]
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.
fn-mote 17 hours ago [-]
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.
runarberg 16 hours ago [-]
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)
They missed another option: require brackets where it would otherwise be ambiguous.
andrepd 16 hours ago [-]
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.
fwlr 14 hours ago [-]
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 12 hours ago [-]
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
10 hours ago [-]
zygentoma 15 hours ago [-]
Exactly this!
It is just plain simpler than the original TeX/LaTeX notation.
vitriol83 15 hours ago [-]
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.
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).
- 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 $αx$ which some flavors of tex do.
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$.
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).
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...
That said, Typst has many good things, like easy to write methods, which this new language should adopt.
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.
I'm pretty sure that's how LyX does it, possibly others as well.
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
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:
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.- 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
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.[1] https://github.com/typst/typst/pull/6442
[2] https://github.com/typst/typst/pull/7084
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.
It may be related to the fact that "mixed numbers" were never part of my curriculum (Wikipedia¹ 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.
¹ https://en.wikipedia.org/wiki/Fraction#Mixed_numbers
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}$.
To give a specific example, I can cite units in the metric system, often written as kg.s⁻².J⁻¹ instead of the more ambiguous kg/s²/J; which could technically be read as kg/(s²/J), giving kg.J.s⁻¹.
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.
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.
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.
Docs: https://typst.app/docs/reference/math/attach/
Latex equation compatibility seems like a blocker for many. Maybe they should have a library that allows one to drop in latex formulas?
another case for using proper notation π with some autosubstitution rules so that you can resolve the ambiguity immediately while typing (if pi is converted into π you backspace and let it stay pi as a function)
But #functions also seems like a good option for readability
I have also heard that the invisible operators help with accessibility. I haven’t tested this on my screen reader, but I suppose <mi>π</mi><mo>⁡</mo><!-->...<--> would read something like “Pi of ...” whereas <mi>π</mi><mo>⁢</mo><!-->...<--> would read something like “Pi times ...” all the while <mi>π</mi><mrow><mo>(</mo> would just read “Pi [open parenthesis] ...”.
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
And since probably many people are very familiar with it, I would have liked for them to just keep that part.
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.
It is just plain simpler than the original TeX/LaTeX notation.
[1]: https://pandoc.org/