F#中的列表理解与高阶函数 [英] List comprehension vs high-order functions in F#

查看:104
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆