F# 6は言語、ライブラリ、ツールに対して豊富な新機能を提供する。パフォーマンスを向上させ、プログラマーが簡単にF# 6に切り替えられることを目指している。
F# 6は、再開可能なコードをベースとして並行性に対する新しい基盤を採用している。これは、非同期コードを開発したり、ステートマシンを生成したりすることに対してパフォーマンスの高い方法である。再開可能なコードは、コンポジション可能で再入可能なコードの定義ができる言語の新しい低レベル機能である。この機能は、関連するResumableCode<'Data, 'T>
デリゲート型を通して直接使うことを意図したものではない。むしろ、新しい計算式を実装するためのベースを提供するものである。
F# 6で再開可能なコードを導入した最初の成果は、新たなtask {}
計算式だ。これは、非同期タスクを作成する際の、よりパフォーマンスの高い方法を提供することを目的としている。F# 5では、非同期タスクを開始するために実行が必要であった。
let readFilesTask (path1, path2) =
async {
let! bytes1 = File.ReadAllBytesAsync(path1) |> Async.AwaitTask
let! bytes2 = File.ReadAllBytesAsync(path2) |> Async.AwaitTask
return Array.append bytes1 bytes2
} |> Async.StartAsTask
タスクを使うことで、明示的なAwaitTask呼び出しを省略できる。
let readFilesTask (path1, path2) =
task {
let! bytes1 = File.ReadAllBytesAsync(path1)
let! bytes2 = File.ReadAllBytesAsync(path2)
return Array.append bytes1 bytes2
}
構文が単純化されたのに加えて、task
のパフォーマンスが大幅に向上している。その下にある完全に異なるメカニズムに依存しているためである。そして、.NETタスクとの相互運用性が改善している。ほとんどの場合、async
の利用をtask
に安全に置き換えることができる。それでも、その2つの間の多くの違いに注意する必要がある。例えば、task
がキャンセルトークンを暗黙的に伝播しないことや、非同期テールコールをサポートしないことなどである。
F#の強力な機能は、入力データにマッチする名前付きパーティションを定義する機能である。その名前をマッチング式で使用できる。これはActiveパターンと呼ばれる。F# 6は構造体表現のサポートによりアクティブパターンをさらに強化している。これにより、基本的に(A|_)
のようなアクティブパターンの定義で、F#の通常のオプション値の代わりにvalue optionを返すことができる。これらの機能を利用するには、Struct
属性を使って、Some
とNone
をそれぞれValueSome
とValueNone
に置き換える必要がある。
[<return: Struct>]
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| true, int -> ValueSome(int)
| _ -> ValueNone
value optionは、常にではないが、多くのシナリオでコードを高速化するのに役立つ。
言語を高速化することを目的としたもう1つの新機能は、新たなInlineIfLambda
属性だ。ラムダ引数とともに使用でき、呼び出し側でインライン化する必要があることを示すものである。インラインラムダは、たとえば多重のループで特に便利である。
言語構文の面では、F# 6はexpr.[idx]
を使ってベクトルにインデックスを付けるというレガシーのOCamlを廃止し、より一般的なexpr[idx]
を採用している。古い構文は引き続き有効だが、新しい構文がインデックス作成の推奨される方法である。警告(/warnon:3566)を有効にして、古い構文を取り除くことができる。
F# 6は、暗黙の整数変換とアップキャスト変換、デバッグの改善、コンパイラの高速化など、ここで説明できるよりもはるかに多くの新機能を提供する。詳細については、公式発表をお見逃しなく。