2009-07-29 4 views
11

Google offre un sacco di esempi di aggiunta e cancellazione di voci in un dizionario F # (o altra raccolta). Ma non vedo esempi per l'equivalente diCome si dichiarano i valori di una voce del dizionario come mutabili?

myDict["Key"] = MyValue; 

Ho provato

myDict.["Key"] <- MyValue 

ho anche tentato di dichiarare il dizionario come

Dictionary<string, mutable string> 

così diverse varianti su Questo. Tuttavia, non ho ancora trovato la combinazione corretta ... se è è effettivamente possibile in F #.

Edit: il codice incriminato è:

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) 

L'errore che sto ottenendo è:

System.NotSupportedException: This value may not be mutated 
    at [email protected]_Item(K key, V value) 
    at <StartupCode$FSI_0036>[email protected](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>[email protected]() 
stopped due to error 

risposta

24

f # dispone di due strutture dati associative comuni:

quello che si sta più abituati, il dizionario mutabile quale eredita che è alla sua presenza nel BCL e utilizza una tabella hash sotto il cofano.

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

L'altro è conosciuto come Map ed è, in stile funzionale comune, immutabile e attuata con alberi binari.

Invece di operazioni che cambierebbero un dizionario, le mappe forniscono operazioni che restituiscono una nuova mappa che è il risultato di qualsiasi modifica richiesta. In molti casi, sotto il cofano non è necessario creare una copia completamente nuova dell'intera mappa, quindi le parti che possono essere condivise normalmente lo sono. Per esempio:

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

Il valore withDouglasAdams rimarrà per sempre come associazione di "tutto" a 42. quindi se fai tardi:

let soLong = Map.remove "everything" withDouglasAdams 

Poi l'effetto di questo 'rimozione' è visibile solo tramite il valore soLong.

La mappa di F # è, come già detto, implementata come un albero binario. La ricerca è quindi O (log n) mentre un dizionario (ben educato) dovrebbe essere O (1). In pratica un dizionario basato su hash tenderà a sovraperformare quello basato su albero in quasi tutti i semplici (basso numero di elementi, bassa probabilità di collisione) in quanto tale è comunemente usato. Detto questo, l'aspetto immutabile della mappa può consentire di utilizzarlo in situazioni in cui il dizionario richiederebbe invece un blocco più complesso o di scrivere più codice "elegante" con minori effetti collaterali e quindi rimane un'alternativa utile.

Questa non è tuttavia la fonte del problema.L'operatore dict restituisce un'implementazione immodificabile IDictionary<K,T> (nonostante non indichi questo nella sua documentazione).

Da fslib-extra-pervasives.fs (nota anche l'uso di opzioni sui tasti):

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")) 
    ... 
+0

il tempo di attività dei siti di ricerca è davvero piuttosto scadente. ecco il link alla cache di google http: http:// 0909.229.132/search?q=cache:GGIlRD9kBnYJ:research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/fsharp.core/microsoft.fsharp. collections.map.html + f% 23 + microsoft.fsharp.collections.map & cd = 1 & hl = it & ct = clnk & gl = uk – ShuggyCoUk

+3

Si noti che la ricerca in un albero binario è O (log n), non O (n log n) come indicato. – kvb

+0

oops - typo thanks – ShuggyCoUk

5

Quale errore si ottiene? Ho provato quanto segue e si compila bene

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

EDIT Verificare che questo codice ha funzionato bene pure.

+0

Interessante ... ho appena fatto mappa [ "foo"] <-. 42 ;; map. ["Foo"] <- 43 ;; OK – telesphore4

+0

Forse è qualcos'altro ... Io cancellerei il post ma non posso – telesphore4

Problemi correlati