How to convert string to regular math?

Just out of curiosity, I tried to automate the generation of this not-so-pretty equation:

$ sum_(i=1)^3 i =& 1 + \
  & 2 + \
  & 3 \
  =& 6 $

I’ve tries this is a few ways:

$ sum_(i=1)^3 i =& #range(1, 4).map(it => [#it]).join([+ \ &]) \
  =& #str(range(1, 4).sum()) $

$ sum_(i=1)^3 i =& #range(1, 4).map(it => str(it)).join([$+$ \ $&$ ]) \
  =& #str(range(1, 4).sum()) $
  
$ sum_(i=1)^3 i =& #range(1, 4).map(it => str(it)).join("+ \n & ") \
  =& #str(range(1, 4).sum()) $

I think there should be a better way to convert strings and numbers to math, but how?

I think this is a perfect use case of Evaluate Function – Typst Documentation — you want to generate typst code and the possible expressions are limited.

#let expr(n) = {
  "sum_(i=1)^{n} i =".replace("{n}", str(n))
  for i in range(1, n) {
    "& {i} + \ ".replace("{i}", str(i))
  }
  "=& {}.".replace("{}", str(n * (n - 1) / 2))
}
#eval(expr(6), mode: "math")

You may also generate it more programmatically as below, but I don’t think that would be more reliable than eval.

#{
  let align-point = $&$.body

  math.equation({
    import sym: eq, plus
    eq
    align-point
    "1"
    plus
    linebreak()

    align-point
    "2"
    plus
  })
}

图片

See also Pack complex content with data loading functions in Tips on debugging Typst code, including the dark magic

#raw(
  yaml.encode($= &1 + \ & 2 +$),
  lang: "yaml",
)
func: equation
block: false
body:
  func: sequence
  children:
  - func: symbol
    text: =
  - func: space
  - func: align-point
  - func: text
    text: '1'
  - func: space
  - func: symbol
    text: +
  - func: space
  - func: linebreak
  - func: space
  - func: align-point
  - func: space
  - func: text
    text: '2'
  - func: space
  - func: symbol
    text: +
3 Likes

Ah, thanks! I guess there is some limitation that I cannot just have a function (e.g. join) insert bits of code into an equation, as I’m familiar to do with LaTeX, so the processing of the code into contents has to be made explicit by eval? Probably this has to do with functions being pure?

How about this? It’s a bit hacky, but physica – Typst Universe and many packages/documents use it.

$ S = #eval(expr(6), mode: "math")  $

It can be done! Without string wrangling or eval or a third party package. The key is not to convert strings and numbers to math, but just use math to begin with.

#let N = 6
$
  sum_(i=1)^#N i =
    #range(1, N).map(num => $& num +$).join($ \ $) \
    & #N \
    =& #range(N + 1).sum()
$

5 Likes