【问题标题】:F# immutable version of List<T>?F# 不可变版本的 List<T>?
【发布时间】:2012-09-16 22:34:34
【问题描述】:

我目前正在尝试学习一点 F# 的乐趣。

在 C# 中,我处理来自数据库的复杂数据,这些数据通常必须在一个元素中包含整数、双精度和字符串。 System.Collections.Generic List&lt;T&gt; 非常适合。

我正在尝试探索 F# 中的并行性,但需要一个不可变的 List&lt;T&gt; 才能这样做。这可能吗?语法是否类似于 C# var x = new List&lt;T&gt;

谢谢。

我将对其进行编辑以使其更清晰:

在 F# 中,我想创建一个不可变的类或记录列表(应该命名),就像在 C# 中使用 List 一样。这样我就可以在同一个元素中使用分组字符串、整数、双精度数。希望这真的很简单。

【问题讨论】:

  • 你想用 F# 并行性做什么?你能说得更具体些吗(举个例子等)?
  • F# 有一个很好的不可变列表类型 - 您可以像 let mylist = 1::b::c::[] 一样设置它。像垫一样,我不确定这里真正的问题是什么
  • 我建议您重新表述您的问题并提供更多详细信息以获得更有意义的答案。不要害羞
  • 对于否决票,您希望我做到多具体,这已经非常清楚我想要实现的目标。我希望如何使用不可变列表完全无关紧要,因为我在这里要做的就是创建一个。
  • 这是用于并行化蒙特卡罗模拟,因此基础数据(来自 RNG 的整数或双精度数组)一旦创建就不可更改。

标签: list f# immutability


【解决方案1】:

我没有投反对票,但如果没有更多细节,很难回答你的问题。

在 F# 中,不可变列表是最常用的数据结构。您经常使用 cons 构造函数(::) 和空列表[] 构造列表。例如,[1; 2; 3]1::2::3::[] 的语法糖。您可以按照@Brian 建议的链接阅读有关基本列表处理的更多信息。

一旦您习惯了 F# 列表,您就可以使用 high-order functions 和列表推导来创建新列表。在您的情况下,可以按如下方式生成随机数列表:

let genRand =
    let rand = System.Random()
    fun () -> rand.NextDouble()

/// Creating a list using high-order functions
let genRandList n = List.init n (fun _ -> genRand())

/// Creating a list using list comprehension
let genRandList' n = [ for i in 1..n -> genRand() ]

我不熟悉蒙特卡罗模拟;但是通读this article,一旦生成随机数列表,您将在列表元素上统一应用几个List.map 函数。出于并行性目的,我建议您使用 Array 而不是 List,这样可以提供更好的加速。数组允许对元素进行随机访问,因此不同的线程可以轻松地并行访问数组的不相交部分。尽管数组是可变的,但由于high-order functions 和数组理解,您可以以无副作用的方式使用它们。

为了使每个元素的任务有意义,您应该将一系列Array.map 合并为一个,并将Array.map 更改为Array.Parallel.map 以实现并行性。您还可以并行化mean 函数;但是,它不太可能给您任何加速。看看this snippet,看看解决方案如何使用数组。

更新

创建记录列表:

type RandPair = { First: float; Second: float}
let genRandPairs n = [ for i in 1..n -> 
                          { First = genRand(); Second = genRand() } ]

classes 也可以这样做。

【讨论】:

  • 感谢您的好评。我习惯在 C# 中像这样使用 List:class MyClass { public int index;公共双号; } var myList = new List myList.Add(new MyClass(1, 0.555));所以我用它来对项目进行分组,这是完美的,因为我从数据库中读取数据,然后对列表中的每个元素和项目执行计算/聚合。因此,在 F# 中,我只看到了作为数据类型的内置结构的示例,而我想做的是创建记录或类的列表。谢谢!
  • @RichardTodd:请参阅上面的更新。我的建议是,在 F# 中编程时,遵循 F# 的方式。否则,您将无法充分利用该语言。
  • @RichardTodd:没问题。你可以投票时可以:)。
【解决方案2】:

在回答如何使用列表之前,您可能需要确定为什么要使用列表

这不是微不足道的,因为我们在计算机科学中称为 List 是一种非常精确的结构,其含义不同于例如 sequence,更多地对应于'list'的随意使用。在 C# 中,这称为 IEnumerable,在 F# 中称为 seq(它们是相同的 BCL 类型)。

序列的这个一般功能概念可以在数组、列表、集合、字典、地图等类型中看到......任何可以枚举

为了让您了解不同的结构,这里是动物学的示例列表(错误..序列):

  • Set 本身是无序的,但即使不是第一次使用也可以枚举
  • List 是一个结构,其中每个元素都有一个指向下一个元素的指针, 允许扫描和 o(n) 随机访问。在 F# 中它是不可变的,您只能创建新的,而不能向其添加元素。你可以有单向遍历的链表,双向遍历的双链表。

  • 数组是一个连续的内存块,允许 o(1) 次随机访问,如果您事先知道集合的大小,那就太好了

  • 字典类似于数组,但由某个非整数键索引
  • ResizableArray 类似于您所知道的 c# List,因为您可以在
  • 中添加元素

关于List本身的一切都在这里

http://en.wikibooks.org/wiki/F_Sharp_Programming/Lists

如果你了解你的程序,你应该能够事先说明为什么你使用这个结构而不是另一个结构。

如果有一天你的程序太慢了,去寻找 'find' 在结构上它们在 o(n) 的位置。 也就是说,相当于数据库中的“全面扫描”。获得正确的结构将使您的程序飞起来

【讨论】:

    【解决方案3】:

    【讨论】:

    • 鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线,如guidelines
    【解决方案4】:

    我认为,在这个问题的上下文中,应该说明 F# 不可变结构对您没有太大帮助,因为如果您按照其他答案中的描述创建不可变 F# 列表,您只能确定您的列表没有被修改,而它持有的引用可能指向不可变的对象。

    也就是说,即使它们是,并行化也不会自动发生。 F# 不是纯语言,所以它不能确定你的对象会引入什么样的副作用,并且不能自己并行化任何东西(即使可以,它也可能不是非常有效的解决方案,因为自动并行化是没那么容易)。

    在下面的问题中有很好的描述:Does F# provide you automatic parallelism?

    当然,这只是一般情况,因为我们不知道您的问题的细节。

    【讨论】:

      猜你喜欢
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 2015-04-09
      相关资源
      最近更新 更多