2011-04-20 86 views

回答

1

seq<'T>类型是编写适用于F#中任何集合的计算的主要方式。有您能与类型工作的几种方法:

  • 您可以使用函数从Seq模块(如Seq.filterSeq.windowed等)
  • 您可以使用序列内涵(如seq { for x in col -> x * 2 }
  • 您可以使用底层(势在必行)IEnumerator<'T>类型,有时需要例如如果要实现自己的收藏夹压缩(通过调用GetEnumerator返回)

这是相对简单的类型,它只能用于从集合中读取数据。因此,您将始终获得类型为seq<'T>的值,该值本质上是一个惰性序列。 F#没有任何用于转换集合的机制(例如,采用集合C到具有新值的集合C的通用函数)或用于创建集合(在Haskell或Scala中可用)的任何机制。

在大多数实际情况下,我没有发现问题 - 大部分工作可以使用seq<'T>完成,当您需要专门的集合(例如数组用于性能)时,通常需要稍微不同的实现无论如何。

+0

谢谢你的回答。因此,如果我想保留关于我的原始集合的类型的信息(比如说,为了避免在以后要将“Knuth shuffle”链接到手动拉链操作时被强制调用'Seq.toArray'),我必须咬子弹和复制粘贴zipWith我想支持的所有集合类型? – 2011-04-20 12:44:32

+1

@Alexander:是的,据我所知,完全不依赖于容器的算法(例如C++中)是不可能的。我想理论上可以在不同的集合类型周围实现面向对象的包装器......但这会值得吗? - Wrt。到'zipWith':所有的收集模块都支持'map2'函数。 – wmeyer 2011-04-20 16:19:50

+0

@wmeyer:谢谢。能够独立于容器实现编写算法对我来说是一个很有价值的特性。据我所知,在大多数实际情况下,缺乏这种能力不是问题,我认为我从根本上不了解如何构建F#代码。 – 2011-04-20 18:17:27

2

集合的泛型编程可以像泛型编程一样进行处理:使用泛型。

let f (map_fun : ('T1 -> 'T2) -> 'T1s -> 'T2s) (iter_fun : ('T2 -> unit) -> 'T2s -> unit) (ts : 'T1s) (g : 'T1 -> 'T2) (h : 'T2 -> unit)= 
    ts 
    |> map_fun g 
    |> iter_fun h 

type A = 
    static member F(ts, g, h) = f (Array.map) (Array.iter) ts g h 
    static member F(ts, g, h) = f (List.map) (List.iter) ts g h 

有点丑陋和冗长,但它是可能的。我正在使用类和静态成员来利用重载。在你的代码中,你可以使用A.F,并调用正确的专业化。

要获得更漂亮的解决方案,请参见https://stackoverflow.com/questions/979084/what-features-would-you-add-remove-or-change-in-f/987569#987569尽管仅针对核心库启用了此功能,但修改编译器以使其在您的代码中不会出现问题。这是可能的,因为编译器的源代码是打开的。

+0

谢谢,Joh。这确实很冗长。 – 2011-04-21 13:59:24