「関数呼出」というのはfoo("bar")のような式のことで、Typstユーザなら誰でも使ったことがあるでしょう。この記事で話題にしたいのは「そもそもfoo(引数)という関数呼出が文法的に可能なのはfooがどの型の値である場合か」ということです。
多くの人は「え、関数呼出可能なのは関数でしょ
」と考えたでしょう。確かに、関数(function値)は関数呼出可能です。でも実は、Typstにはfunction以外にも「関数呼出可能」な値をもつ型が存在します。
型値(type値)
「型値」というのはトップレベルでstrやint等で参照できる1「型を表す値」であり、Typstのプログラミングにおいて入力値の型を調べたいときに使われます。
if type(input) == str {
// inputは文字列(str型)
} else if type(input) == int {
// inputは整数(int型)
} else {
// それ以外
}
でもよく考えてみると、“strやintという名前のもの”は「(文字列や整数に)型変換する」場合にも用いられます。
// int値をstr値に変換する(16進法)
#str(129414, base: 16)
// float値をint値に変換する
#int(calc.pi)
この式はどう見ても「関数呼出」です。とすると、strやintは関数(function値)なのでしょうか? type()で調べてみましょう。
#type(str) #type(int)
やっぱり「型値」はtype2という独自の型を持っているのでした。つまり、「関数だけでなく型値も関数呼出が可能である」ということになります。
型値で関数呼出をする用法のことを「コンストラクタ(constructor)」と呼びます。Typstの型についてのドキュメント(例えばstr型)を見ると“Constructor”という節が置かれている場合がありますが、これはstr(引数)のように関数呼出をする用法についての説明です。
コンストラクタの処理内容は型によってまちまちです。「当該型への型変換」である場合が多いですが、必ずしもそうとは限りません3。ただ恐らく「当該型の値を返す」処理である、というのは成り立ちそうです。
注意点として、全ての型値がコンストラクタの用法をもつわけではありません。例えば、bool(真偽値)やlength(長さ値)は関数呼出ができません。
bool(0)
//==> ❌エラー: type boolean does not have a constructor
length(0)
//==> ❌エラー: type length does not have a constructor
Typstのこのような型値の性質はPythonによく似ている感じがしています。
シンボル(symbol値)
Typstの数式モードでarrowと書く4と“→”の記号が出力されます。
$A arrow B$
Typstの文法マニアの人ならこのarrowがsymbol型の値だということは知っているでしょう(多分
)
ところが、accent()関数のドキュメントにあるように、このaccentは関数呼出の形式で「文字に“→”のアクセントを付ける」のにも使用できます。
$arrow(x)$
これだけ見ると「数式関数呼出だから何か変なことが起こっている」という気もしますが、そうではありません。このarrowは数式外ではsym.arrowとして参照できますが、数式外のsym.arrowもやはり関数呼出できます。つまり、「シンボル(symbol値)も関数呼出が可能である」というわけです。
#sym.arrow /
// これは"sym.arrow([0])"と同等なので関数呼出である
#sym.arrow[0]
例によって、全てのシンボルが関数呼出可能であるわけではありません。恐らくaccent()関数がサポートしている記号に限られるのでしょう。
// "emoji.face.inv"もsymbol値だが…
#emoji.face.inv[z]
// ==> ❌エラー: symbol 🙃 is not callable
symbol型の値はsymbolのコンストラクタでユーザが生成できます。この場合も対象の文字が「サポートしている記号」に含まれるならば生成した値は関数呼出可能になるようです。
// "arrow.l.r"と同じ矢印(U+2194)
// ※ここでは"([0])"の丸括弧を省略できないことに注意
#symbol("↔")([0])
関数モドキと関数の差異
ここまで「関数モドキ」、すなわち「関数ではないが関数呼出が可能な値」の話をしてきました。関数モドキはほとんどの場合に関数と同じように振る舞いますが、挙動が異なる部分もあります。
function型のメソッドにwith()というものがあり、これは「引数を部分適用する」という機能をもちます。
// 赤色で出力する関数
#let redden = text.with(fill: red)
// "text(fill:red)[great!]"と同等になる
Typst is #redden[great!]
これを見ると、str()でも同じことができそうな気がします。しかしstrのような関数モドキはfunction値ではないため、当然functionのメソッドは使えないのです。
// "16進法の文字列に変換する関数"を作りたいが…
#let hex-str = str.with(base: 16)
// ❌エラー: type string does not contain field `with`
こういう場合は「関数モドキを本物の関数に変換する処理」を挟む必要があります。
// 16進法の文字列に変換する関数
// ※関数リテラルで書いたものは当然関数(function値)である
#let hex-str = ((..args) => str(..args)).with(base: 16)
// "str(base:16, 129414)"と同等
#hex-str(129414)
まとめ
というわけで皆さん、「Typst Advent Calendar 2025」は明日以降の記事(または昨日の記事
)に期待しましょう!![]()








