13

Google は、F# ディクショナリ (またはその他のコレクション) にエントリを追加および削除する例を数多く提供しています。しかし、私は同等の例を見ません

myDict["Key"] = MyValue;

私はもう試した

myDict.["Key"] <- MyValue

また、辞書を次のように宣言しようとしました

Dictionary<string, mutable string>

これにはいくつかのバリエーションがあります。しかし、私はまだ正しい組み合わせを見つけていません...実際F#で可能であれば.

編集:問題のあるコードは次のとおりです。

type Config(?fileName : string) =
    let fileName = defaultArg fileName @"C:\path\myConfigs.ini"

    static let settings =
        dict[ "Setting1", "1";
              "Setting2", "2";
              "Debug",    "0";
              "State",    "Disarray";]

    let settingRegex = new Regex(@"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))")

    do  File.ReadAllLines(fileName)
        |> Seq.map(fun line -> settingRegex.Match(line))
        |> Seq.filter(fun mtch -> mtch.Success)
        |> Seq.iter(fun mtch -> settings.[mtch.Groups.Item("key").Value] <- mtch.Groups.Item("value").Value)

私が得ているエラーは次のとおりです。

System.NotSupportedException: This value may not be mutated
   at Microsoft.FSharp.Core.ExtraTopLevelOperators.dict@37-2.set_Item(K key, V value)
   at <StartupCode$FSI_0036>.$FSI_0036_Config.$ctor@25-6.Invoke(Match mtch)
   at Microsoft.FSharp.Collections.SeqModule.iter[T](FastFunc`2 action, IEnumerable`1 sequence)
   at FSI_0036.Utilities.Config..ctor(Option`1 fileName)
   at <StartupCode$FSI_0041>.$FSI_0041.main@()
stopped due to error
4

2 に答える 2

28

f#には、2つの一般的な連想データ構造があります。

あなたが最も慣れているもの、それが継承する可変ディクショナリは、BCLに存在し、内部でハッシュテーブルを使用します。

let dict = new System.Collections.Generic.Dictionary<string,int>()
dict.["everything"] <- 42

もう1つはマップと呼ばれ、一般的な機能スタイルでは不変であり、バイナリツリーで実装されます。

ディクショナリを変更する操作の代わりに、マップは、要求された変更の結果である新しいマップを返す操作を提供します。多くの場合、内部ではマップ全体のまったく新しいコピーを作成する必要がないため、通常は共有できる部分があります。例えば:

let withDouglasAdams = Map.add "everything" 42 Map.empty

withDouglasAdamsは、42への「すべて」の関連付けとして永久に残ります。したがって、後で行う場合:

let soLong = Map.remove "everything" withDouglasAdams

この場合、この「削除」の効果は、値を介してのみ表示されsoLongます。

F#のマップは、前述のように、バイナリツリーとして実装されています。したがって、ルックアップはO(log n)ですが、(正常に動作する)辞書はO(1)である必要があります。実際には、ハッシュベースの辞書は、一般的に使用されているほとんどすべての単純な(要素数が少なく、衝突の可能性が低い)ツリーベースの辞書よりもパフォーマンスが優れている傾向があります。とはいえ、マップの不変の側面により、辞書がより複雑なロックを必要とする状況で使用したり、副作用の少ないより多くの「エレガントな」コードを記述したりできる可能性があります。

ただし、これは問題の原因ではありません。dict'operator'は、明示的に不変のIDictionary<K,T>実装を返します(ドキュメントにこれが示されていませんが)。

fslib-extra-pervasives.fsから(キーのオプションの使用にも注意してください):

let dict l = 
    // Use a dictionary (this requires hashing and equality on the key type)
    // Wrap keys in an Some(_) option in case they are null 
    // (when System.Collections.Generic.Dictionary fails). Sad but true.
    let t = new Dictionary<Option<_>,_>(HashIdentity.Structural)
    for (k,v) in l do 
        t.[Some(k)] <- v
    let d = (t :> IDictionary<_,_>)
    let c = (t :> ICollection<_>)
    let ieg = (t :> IEnumerable<_>)
    let ie = (t :> System.Collections.IEnumerable)
    // Give a read-only view of the dictionary
    { new IDictionary<'key, 'a> with 
            member s.Item 
                with get x = d.[Some(x)]            
                and  set (x,v) = raise (NotSupportedException(
                                            "This value may not be mutated"))
   ...
于 2009-07-29T22:19:04.027 に答える
7

どのようなエラーが表示されますか? 私は次のことを試しましたが、問題なくコンパイルされます

let map = new System.Collections.Generic.Dictionary<string,int>()
map.["foo"] <- 42

EDITこのコードも問題なく動作することを確認してください。

于 2009-07-29T21:41:58.843 に答える