gpt4 book ai didi

f# - 如何将字典条目的值声明为可变的?

转载 作者:行者123 更新时间:2023-12-04 00:07:19 25 4
gpt4 key购买 nike

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

最佳答案

f# 有两种常见的关联数据结构:

你最习惯的是它继承的可变字典,它存在于 BCL 中,并在底层使用哈希表。

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

另一个被称为 Map并且,在常见的函数风格中,是不可变的,并用二叉树实现。

map 提供的操作不是更改字典的操作,而是返回新 map 的操作,该新 map 是请求的任何更改的结果。在许多情况下,引擎盖下不需要制作整个 map 的全新副本,因此可以正常共享的部分是。例如:
let withDouglasAdams = Map.add "everything" 42 Map.empty

withDouglasAdams将永远作为“一切”与 42 的关联而存在。因此,如果您以后这样做:
let soLong = Map.remove "everything" withDouglasAdams

那么这种“删除”的效果只能通过 soLong 可见。值(value)。

如前所述,F# 的 Map 是作为二叉树实现的。因此,查找是 O(log n) 而一个(表现良好的)字典应该是 O(1)。在实践中,基于哈希的字典在几乎所有简单(元素数量少,冲突概率低)的情况下往往会优于基于树的字典,因为它是常用的。这就是说 Map 的不可变方面可能允许您在字典需要更复杂的锁定或编写更“优雅”且副作用更少的代码的情况下使用它,因此它仍然是一个有用的替代方案。

然而,这不是您问题的根源。 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"))
...

关于f# - 如何将字典条目的值声明为可变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1203209/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com