🔍

Statically Resolved Type Parameters の地味な使いどころ

2023/12/14に公開

STRP; Statically Resolved Type Parameters(静的に解決される型パラメーター)の地味な使いどころを紹介します。

さっそくコードを。

open System.Collections

module Array =
    let inline ofCollection (collection : 'Collection & #ICollection when 'Collection : (member Item : int -> 'Item with get)) =
        let arr = Array.zeroCreate<'Item> collection.Count
	collection.CopyTo(arr, 0)
	arr

非ジェネリック版ICollectionはどんな型を保持しているか表面上は見えないです。
しかしその実装クラスは往々にして配列互換のためインデクサを定義していてます。つまりインデクサの戻り値を見れば保持している型を知ることができます。
ここでSTRPの出番です。「そんなメンバー定義があるんじゃろ?」として「その戻り値型を教えて?('Item)」とできます。
結果、 Array.ofCollection : 'Collection -> 'Item[] という配列への変換関数が作れます。

なお.NETの型定義では「そんなメンバー定義があるんじゃろ?」「その戻り値型を教えて?('Item)」の部分が表現できないため、インライン展開が必須となり、F#言語以外からは呼び出すことができません。

使い方は次のようになります。

let matches = Regex.Matches(input, pattern) |> Array.ofCollection

これで、matchesは型ヒントなしでMatch[]に変換されます。

この記事は概ね、Regex.Matchesの結果クラスMatchCollectionが(.NET Frameworkでは今なお)ICollectionしか実装していないことへの恨みで書かれています。

Discussion