📘

Verse言語の設計思想を読み解きたい(20) 型システム④ 型エイリアスと型マクロ

2023/05/03に公開

前回はこちら

https://zenn.dev/t_tutiya/articles/0f758b633a3ba6

型エイリアスと型マクロ

今回は型エイリアスと型マクロについて。

Verseでは、型は first class value[1] とされています。これは、Verseでは値と同じように、型を変数に代入して取り扱えるという意味です(型同士を値のように足したり引いたり出来るわけではないです)。

Verseではint型やfucntion型のように「type型(type type)」の変数定義が出来るのだと考えると分かりやすいかもしれません。

大きく分けて「型エイリアス」はプリミティブ型から型定義する方法、「型マクロ」はfunction型から型定義する方法になります。どちらもそこまで複雑でもないので、公式ドキュメントにあるサンプルコードをベースにさらっと解説します。

型エイリアス(Type Aliasing)

https://dev.epicgames.com/documentation/ja-jp/uefn/type-aliasing-in-verse
型エイリアス(Type Aliasing)」は、組み込みの型を別名で再定義する物です。

例えば、以下のコードではint型の別名としてnumberを定義しています。

number := int

型エイリアスは既存の型の別名に過ぎないので、例えばnumberは以下の様にint型と互換性があります。

number := int
arg1 : number = 0
arg2 : int = arg2

タプルの構成要素を固定した型エイリアスを作る事も出来ます。

int_triple := tuple(int, int, int)
RotateInts(X : int_triple) : int_triple =
    (X(3), X(1), X(2))

RotateInts関数は、引数としてtuple(int, int, int)型を取ります。
上の関数は以下の様に書いた場合と同じです。

RotateInts(X : tuple(int, int, int)) : tuple(int, int, int) =
    ( X(3), X(1), X(2))

int_tripleの部分が置換されているだけなのがわかります。

型エイリアスを使う事でコードの冗長性を減らせると見るか、見通しが悪くなると見るかは、好みによりそうです。

注意

現時点では、パラメータ型の型エイリアスは作成できません[2]。これについてはパラメータ型の記事で取り上げます。

型マクロ(Type Macro)

https://dev.epicgames.com/documentation/ja-jp/uefn/type-macro-in-verse
型マクロ(Type Macro)」は、type式を使ってfunction型を定義する物です。

型エイリアスは関数のボディでも記述出来ますが、type式はモジュールスコープでしか記述できません。

type式では、「仮引数名を省略した関数のインターフェイス定義」とでも言うべき、独特な形式でfunction型を定義します。

以下は、type式を使って「引数にint型を取り、戻り値がint型の関数」を表すfunction型funcAを定義します。

functorA := type{Func(:int):int}

type式のボディに記述されたFunc(:int):intがfunction型の定義になります。括弧内は(x :int)の仮引数名xが省略されていると考えると分かりやすいかもしれません。

また、便宜上Funcという関数名を設定していますが、この名前は外部から参照される事がありません。このような場合は、以下の様に_識別子を使って匿名の関数を定義出来ます。

functorA := type{_(:int):int}

型マクロの使用例

前回、2つの関数を任意に呼び出せる関数を紹介しました。あの処理は、型マクロを使ってもっと分かりやすい実装に出来ます。

FuncI2IA(x :int) :int = x + 2
FuncI2IB(x :int) :int = x * 2

var FunctorI2I : type{_(:int) :int} = FuncI2IA

Print("{FunctorI2I(6)}")
set FunctorI2I = FuncI2IB
Print("{FunctorI2I(6)}")

FunctorI2I関数はまるで格納された関数その物であるかのように振る舞います。このような関数の事をファンクタ(閉包関数)と呼びます[3]

補足

公式ドキュメントの型マクロのページには以下の様なサンプルコードがあります。

Foo() : int = 0
Bar(X : type{Foo()}) : type{Foo()} = X

既存の関数(ここではFoo())からインターフェイスを参照してfunction型を定義出来のだと思いますが、このコードは現時点では以下のエラーが出てコンパイル出来ません。

type does not yet support subexpressions other than function declarations and 'where' clauses.(3552)
私訳 :typeは、関数宣言および`where`句以外の部分式を現時点ではサポートしていません(3552)。

恐らく将来的にサポートされるのだと思います。ご注意下さい。

続く

次回はパラメータ型。型システムシリーズ最終回の予定です。

#Fortnite #Verse #VerseLang #UEFN

続き

https://zenn.dev/t_tutiya/articles/a39c27ba935c4f

脚注
  1. 一般には"first class object"と呼ぶと思いますが、同じ意味なのか違う意味なのかわかりませんでした。 ↩︎

  2. 恐らく将来的に対応予定 ↩︎

  3. C#のデリゲート、C++の関数テンプレートなどが機能として近いです ↩︎

Discussion