Expert F# の本を読んでいて、このコードを見つけました
open System.Collections.Generic
let divideIntoEquivalenceClasses keyf seq =
// The dictionary to hold the equivalence classes
let dict = new Dictionary<'key,ResizeArray<'T>>()
// Build the groupings
seq |> Seq.iter (fun v ->
let key = keyf v
let ok,prev = dict.TryGetValue(key)
if ok then prev.Add(v)
else let prev = new ResizeArray<'T>()
dict.[key] <- prev
prev.Add(v))
dict |> Seq.map (fun group -> group.Key, Seq.readonly group.Value)
および使用例:
> divideIntoEquivalenceClasses (fun n -> n % 3) [ 0 .. 10 ];;
val it : seq<int * seq<int>>
= seq [(0, seq [0; 3; 6; 9]); (1, seq [1; 4; 7; 10]); (2, seq [2; 5; 8])]
まず私にとって、このコードは本当に醜いです。たとえこれが安全であっても、関数型言語よりも命令型言語に似ているように見えます..特に clojure と比較して. しかし、問題はこれではありません...辞書の定義に問題があります
これを入力すると:
let dict = new Dictionary<'key,ResizeArray<'T>>();;
私はこれを得る:
pruebafs2a.fs(32,5): error FS0030: Value restriction. The value 'dict' has been inferred to have generic type
val dict : Dictionary<'_key,ResizeArray<'_T>> when '_key : equality
Either define 'dict' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
大丈夫ですか?...
本当にありがとう
質問を改善する:
わかりました、値の制限について読んでいて、この役立つ情報を見つけました
特に、関数定義と単純な不変データ式のみが自動的に一般化されます。
...わかりました..これは理由を説明しています
let dict = new Dictionary<'key,ResizeArray<'T>>();;
動作しません...そして4つの異なるテクニックを示していますが、私の意見ではエラーを解決するだけで、汎用コードを使用するための解決策ではありません:
手法 1: 値を非ジェネリックに制限する
let empties : int list [] = Array.create 100 []
手法 3: 必要に応じてジェネリック関数にダミー引数を追加する
let empties () = Array.create 100 []
let intEmpties : int list [] = empties()
手法 4: 必要に応じて明示的な型引数を追加する (tec 3 と同様)
let emptyLists = Seq.init 100 (fun _ -> [])
> emptyLists<int>;;
val it : seq<int list> = seq [[]; []; []; []; ...]
----- そして、本当のジェネリック コードを使用させてくれる唯一の方法 ------ テクニック 2: ジェネリック関数に明示的な引数があることを確認する
let mapFirst = List.map fst //doesn't work
let mapFirst inp = List.map fst inp
わかりました、4 つの手法のうち 3 では、これを使用する前に一般的なコードを解決する必要があります...今...本の例に戻ります...コンパイルが 'key と 'T の値を知っているとき
let dict = new Dictionary<'key,ResizeArray<'T>>()
スコープ内では、キーを任意の型にするためのコードは非常に一般的です。'T でも同じことが起こります。
最大のダミーの質問は次のとおりです。
コードを関数で囲む場合 (テクニック 3):
let empties = Array.create 100 [] //doesn't work
let empties () = Array.create 100 []
val empties : unit -> 'a list []
I need define the type before begin use it
let intEmpties : int list [] = empties()
私にとっては (確かに私は静的型言語については少しばかげています)、これは本当のジェネリックではありません。使用時に型を推測できないためです。型を定義してから値を渡す必要があります (渡された値) 他の方法で存在し、それほど明示的でなくても型を定義できます..
どうもありがとう..本当に助けてくれてありがとう