简体   繁体   English

F#是否与Haskell相当?

[英]Does F# have an equivalent to Haskell's take?

In Haskell, there is a function "take n list" which returns the first n elements from a list. 在Haskell中,有一个函数“take n list”,它返回列表中的前n个元素。 For example "sum (take 3 xs)" sums up the first three elements in the list xs. 例如,“sum(take 3 xs)”总结了列表xs中的前三个元素。 Does F# have an equivalent? F#有同等价值吗? I expected it to be one of the List-functions, but I can't spot anything that seems to match. 我希望它是List函数之一,但我找不到任何似乎匹配的东西。

To clarify a few things, the difference between Seq.take and Seq.truncate (as pointed out by @sepp2k) is that the second one will give you a sequence that returns at most the number of elements you specified (but if the length of the sequence is less, it will give you less elements). 为了澄清一些事情, Seq.takeSeq.truncate之间的差异(由@ sepp2k指出)是第二个将给你一个序列,它最多返回你指定的元素数量(但如果长度为顺序较少,它会给你更少的元素)。

The sequence generated Seq.take function will throw an exception if you try to access an element beyond the length of the original list (Note that the Seq.take function doesn't throw the exception immediately, because the result is lazily generated sequence). 如果您尝试访问超出原始列表长度的元素,则生成的序列Seq.take函数将抛出异常(请注意, Seq.take函数不会立即抛出异常,因为结果是延迟生成的序列)。

Also, you don't need to convert the list to a sequence explicitly. 此外,您不需要显式将列表转换为序列。 Under the cover, list<'a> is a .NET class that inherits from the seq<'a> type, which is an interface. 在封面下, list<'a>是一个继承自seq<'a>类型的.NET类,它是一个接口。 The type seq<'a> is actually just a type alias for IEnumerable<'a> , so it is implemented by all other collections (including arrays, mutable lists, etc.). 类型seq<'a>实际上只是IEnumerable<'a>的类型别名,因此它由所有其他集合(包括数组,可变列表等)实现。 The following code will work fine: 以下代码可以正常工作:

let list = [ 1 .. 10 ]
let res = list |> Seq.take 5

However, if you want to get a result of type list<int> you'll need to convert sequence back to a list (because a list is more specific type than a sequence): 但是,如果要获取类型list<int>的结果,则需要将序列转换回列表(因为列表的类型比序列更具体):

let resList = res |> List.ofSeq

I'm not sure why F# libraries don't provide List.take or List.truncate . 我不确定为什么F#库不提供List.takeList.truncate I guess the goal was to avoid reimplementing the whole set of functions for all types of collections, so those where the implementation for sequences is good enough when working with a more specific collection type are available only in the Seq module (but that's only my guess...) 我的目标是避免为所有类型的集合重新实现整个函数集,所以那些使用更具体的集合类型的序列实现足够好的那些只在Seq模块中可用(但这只是我的猜测...)

Yeah, it's called Seq.take . 是的,它被称为Seq.take Usage seems to be identical to Haskell's: Seq.take count source . 用法似乎与Haskell的相同: Seq.take 计数源 To use it on a list, use List.toSeq first. 要在列表中使用它, List.toSeq首先使用 List.toSeq (Update: Apparently from the comments, this isn't necessary.) (更新:显然,从评论来看,这不是必需的。)

Seq.take works, as others already have stated, but all Seq operations on a list come at a cost. Seq.take正如其他人已经说过的那样有效,但是列表上的所有Seq操作都需要付出代价。 In the case of Seq.take, it's not surprising, as the list has to be copied. 在Seq.take的情况下,这并不奇怪,因为必须复制列表。

It's more noteworthy that, for example, Seq.concat on a list takes a lot more time than List.concat. 更值得注意的是,例如,列表中的Seq.concat比List.concat需要更多的时间。 I suppose that implies that you don't just access the list as a seq when you call a Seq.xxx function, but that the list in copied/converted to a Seq behind the scenes as well. 我想这意味着当你调用Seq.xxx函数时,你不只是作为seq访问列表,而是在后台复制/转换为Seq的列表。

edit: The reason I drew the conclusion above, was this bench using F# interactive: 编辑:我之所以得出上述结论的原因,是这个使用F#interactive的工作台:

#time "on";;
let lists = [for i in 0..5000000 -> [i..i+1]];;
Seq.length (Seq.concat lists);;
List.length (List.concat lists);;

On my machine, the List.length version takes about 1.9 secs , whereas the Seq.length version takes about 3.8 secs (shortest time of a few repeated tests of the length lines only, excluding the list generation line). 在我的机器上, List.length版本大约需要1.9秒 ,而Seq.length版本需要大约3.8秒 (仅对长度行进行一些重复测试的最短时间,不包括列表生成行)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM