F#中的列表理解与高阶函数 [英] List comprehension vs high-order functions in F#
问题描述
我来自SML背景,对高阶函数感到很自在.但是我真的不了解列表理解的概念. 在List
上是否有列表理解比高阶函数更合适的情况?反之亦然?
I come from SML background and feel quite comfortable with high-order functions. But I don't really get the idea of list comprehension. Is there any situation where list comprehension is more suitable than high-order functions on List
and vice versa?
我听说某个地方的列表理解要比高阶函数慢,在编写对性能有要求的函数时,我应该避免使用它吗?
I heard somewhere that list comprehension is slower than high-order functions, should I avoid to use it when writing performance-critical functions?
在此示例中,请查看投影列表F#中有效地列出列表,其中@cfern的答案分别包含两个使用列表理解和高阶函数的版本:
For the example' sake, take a look at Projecting a list of lists efficiently in F# where @cfern's answer contains two versions using list comprehension and high-order functions respectively:
let rec cartesian = function
| [] -> [[]]
| L::Ls -> [for C in cartesian Ls do yield! [for x in L do yield x::C]]
和:
let rec cartesian2 = function
| [] -> [[]]
| L::Ls -> cartesian2 Ls |> List.collect (fun C -> L |> List.map (fun x->x::C))
推荐答案
在理解和高阶函数之间的选择主要是样式问题.我认为理解有时更容易理解,但这只是个人喜好.注意,cartesian
函数可以这样写得更优雅:
Choosing between comprehensions and higher-order functions is mostly a matter of style. I think that comprehensions are sometimes more readable, but that's just a personal preference. Note that the cartesian
function could be written more elegantly like this:
let rec cartesian = function
| [] -> [[]]
| L::Ls ->
[ for C in cartesian Ls do for x in L do yield x::C ]
有趣的情况是编写递归函数时.如果使用序列(和序列推导),它们会删除一些不必要的临时列表分配,并且如果在尾部调用位置使用yield!
,还可以避免堆栈溢出异常:
The interesting case is when writing recursive functions. If you use sequences (and sequence comprehensions), they remove some unnecessary allocation of temporary lists and if you use yield!
in a tail-call position, you can also avoid stack overflow exceptions:
let rec nums n =
if n = 100000 then []
else n::(nums (n+1))
// throws StackOverflowException
nums 0
let rec nums n = seq {
if n < 100000 then
yield n
yield! nums (n+1) }
// works just fine
nums 0 |> List.ofSeq
这是一个非常有趣的模式,因为不能使用列表以相同的方式编写它.使用列表时,您不能返回某些元素然后进行递归调用,因为它对应于n::(nums ...)
,它不是尾递归.
This is quite an interesting pattern, because it cannot be written in the same way using lists. When using lists, you cannot return some element and then make a recursive call, because it corresponds to n::(nums ...)
, which is not tail-recursive.
这篇关于F#中的列表理解与高阶函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!