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.
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?
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.
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.
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.
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.
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.
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.
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)
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 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.
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).
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].
> 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.
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.
>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
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.
24 comments
[ 2.2 ms ] story [ 52.3 ms ] threadI 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.
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.[1] https://github.com/typst/typst/pull/6442
[2] https://github.com/typst/typst/pull/7084
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.
And since probably many people are very familiar with it, I would have liked for them to just keep that part.
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).
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
I'm pretty sure that's how LyX does it, possibly others as well.
- 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.
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
Latex equation compatibility seems like a blocker for many. Maybe they should have a library that allows one to drop in latex formulas?
Docs: https://typst.app/docs/reference/math/attach/