matarillo.com

The best days are ahead of us.

9.4 F# 1.0 -- 機能コアの改善:オーバーロードされた演算

2021-09-25 00:00:21

OCamlの明白な問題の中にはオーバーロードされた演算の問題がありました。 OCamlはHaskell方式の型クラスを追加する(後述します)ことを避け、代わりに整数や浮動小数点数の演算に対し、語句の構成的にあいまいな(訳注:syntax-ambiguated)アプローチを採用しました。

let x1 = 1 + 1 (* 整数 *)
let x2 = 1.0 +. 2.0 (* 浮動小数点数 + ではなく +. であることに注意 *)

このアプローチはシンボリックプログラミングには実用的でした。数値型を広く使用しないからです。 ですが、この分野に独自の基準を持つ.NETのコンテキストでは実用的ではありませんでした。 例えば、オーバーロードされた算術をサポートする型は、静的メンバー呼び出し op_Addition などをサポートすることによってこれを示します。 この問題を解決するためのF# アプローチは、HM(X)とG’Caml(OCamlでこれらの問題を扱うための提案)に関する研究[Furuse 2002]に触発されました。 特に、「メソッド制約」が追加されました。これには、奇妙な形式の構文を意図的に導入しました。

let inline (+) (x: ^T) (y: ^U) : ^V =
    ((^T or ^U): (static member op_Addition : ^T * ^U -> ^V) (x, y))

この定義によれば、+の使用はすべて、適切に型指定された op_Addition メソッドへの呼び出しをインライン化することによって実装されます。 メソッドは型 ^T または ^U 、すなわち左引数または右引数の型に定義されている必要があります。 型変数の ^T の表記は、静的に解決される型パラメーター(SRTP)、すなわち、コンパイル時に公称型に解決される型パラメーターを示します。 この構文をサポートするためだけに inline キーワードがF# に追加されました: インライン化することにより、使用時に利用可能な型に従って制約が解決されます。 これにより、オーバーロードされた算術演算をHindley-Milner型推論ときちんと統合し、コードをより自然な形にすることができます。

let x1 = 1 + 1     // 整数
let x2 = 1.0 + 2.0 // 浮動小数点数
let x3 = DateTime.Now + TimeSpan.Years(1.0) // 日付

SRTPはその後、制約されたジェネリクスのメカニズムとして、F# でさらに一般的に使用されるようになりましたが、 元々はオーバーロードされた算術演算に対処するために特別に設計されたものです。

この時期には、オーバーロードされた算術に対する多くの代替アプローチが存在していました。 Haskellの型クラス[Hudak et al. 2007; Peyton Jones et al. 1997; Wadler and Blott 1989]やC++のテンプレート[Stroustrup 2013]はいずれも筆者がよく知っていました。 SRTP制約に関してジェネリックなコードにインラインを使用するのは、ほぼすべてのC++コンパイラーが使用しているインライン化、フラット化、特殊化のプロセスにヒントを得ています。 Haskellスタイルの型クラスは、コードを分類、整理、構造化するために、新しい種類のトップレベル宣言を言語に追加することになるので、解決策としては却下されました – Haskellではこれを「クラス」と呼んでいますが、オブジェクトプログラミングの用語と齟齬をきたすので、新たな用語が必要になったでしょう。 それに、F# 1.0に含まれるオブジェクトプログラミングの構成体との間には、解決すべき多くの技術的な設計上の相互作用があったでしょう。 もう一つの懸念はパフォーマンスです。 型クラスは通常、「証人渡し(witness-passing)」によって実装されています。このため、算術演算コードをほんの少し変更しただけで、証人の間接呼び出しにより、コードのパフォーマンスが大きく変化するという事態が発生します。 このようなパフォーマンスの不連続性は、C++のテンプレートやSRTPのコードインライン化アプローチを使用した場合には見られません。 最後に、型クラスはこの時期にかなりの研究が行われ、進化を遂げている途中でした。たとえば、Simon Peyton-Jonesの研究では、型クラスをオブジェクトプログラミング機能と組み合わせることが検討されていました。 この研究では、かなりの複雑さが追加されるだけのように思えました。 しかし、型クラスは今日でもF# の機能としてよく要望が上がります。このことは、この論文の最後にあるふりかえりで議論されています。


インデックスへ戻る