我的问题是在输入Seq.
时为什么没有Seq.tail
功能?
在不将序列转换为列表的代码中,递归函数中没有Seq.tail
函数。是因为Seq.initInfinte
用于创建序列,还是有其他原因?
open System
let readList() =
Seq.initInfinite (fun _ -> Console.ReadLine())
|> Seq.takeWhile (fun s -> (s <> ""))
|> Seq.map (fun x -> Int32.Parse(x))
let rec listLen list1 acc =
if Seq.isEmpty list1 then
acc
else
(* There is no Seq.tail available. Compile error. *)
listLen (Seq.tail list1) (acc + 1)
[<EntryPoint>]
let main argv =
let inList = (readList())
let inListLen = listLen inList 0
printfn "%A" inListLen
0 // return an integer exit code
然而,这很好用。我很困惑为什么Seq.tail
不可用,但List.tail
可用。
open System
let readList() =
Seq.initInfinite (fun _ -> Console.ReadLine())
|> Seq.takeWhile (fun s -> (s <> ""))
|> Seq.map (fun x -> Int32.Parse(x))
let rec listLen list1 acc =
if List.isEmpty list1 then
acc
else
listLen (List.tail list1) (acc + 1)
[<EntryPoint>]
let main argv =
let inList = Seq.toList (readList())
let inListLen = listLen inList 0
printfn "%A" inListLen
0 // return an integer exit code
答案 0 :(得分:6)
没有具体原因,它只是从未被添加,就是这样。虽然它可以在更高版本的F#中使用(在4.0中规范集合API的工作量很大)。
然而,人们可以提供一个常识论证,为什么Seq.tail
稍微有用,甚至可能是危险的。这实际上可能是最初没有添加它的原因,但我不确定。
你看,列表和序列在幕后有不同的表现形式。
List是一个包含两个字段的数据结构:第一个元素(称为“head”)和其余元素,它本身只是另一个列表(称为“tail”)。所以调用List.tail
意味着仅仅采用数据结构的第二个字段。没有复杂的处理,只需要采用其中一个数据结构字段。
IEnumerable.GetEnumerator
),它返回一个可变数据结构(称为IEnumerator
),可以反复“踢”(通过调用{{1每次踢球时产生下一个项目,并改变其内部状态
这个表示意味着,为了“删除”序列的第一个元素,必须采用原始序列并将其包装在另一个函数中,当被要求生成IEnumerator.MoveNext
时,将获得内部序列序列的IEnumerator
,然后踢一次,然后返回给调用者。沿着这些方向的东西(伪代码):
IEnumerator
这意味着,对于列表,每次调用Tail(inner).GetEnumerator =
let innerE = inner.GetEnumerator()
innerE.MoveNext()
innerE
都会使数据结构更少复杂(少一个项目,只剩下尾部),每次调用{{1会使它更多复杂(另外一个函数包装器)。更重要的是,如果你连续几次取一个tail
的序列,然后迭代结果,你仍然会迭代整个原始序列,即使在逻辑上它看起来更短。
将此问题应用于您的具体案例,基于tail
的{{1}}实施将具有二次复杂性(而不是列表的线性),因为每次调用tail
时,都会有效地导致迭代到第一个非跳过的项目,每次递归调用listLen
将添加另一个跳过的项目进行迭代。
对于它的价值,标准的.NET LINQ实际上有一个等效的操作 - 名为Seq.tail
,你可以完全使用它来自F#:
Seq.isEmpty
或者,正如罗伯特·尼尔森在评论中指出的那样,即使在F#标准库中也是listLen
(我用手机写的,当时无法验证):
.Skip
答案 1 :(得分:6)
F#3.x中没有Seq.tail。它在F#4.x中可用。我确认您的代码在4.0中编译,但不是3.1。
在F#4.0中添加了许多功能,以及#34;规范&#34; List,Array和Seq。
https://github.com/fsharp/fslang-design/blob/master/FSharp-4.0/ListSeqArrayAdditions.md
(我注意到Option在这个问题上被遗漏了,但怀疑它在某些时候也有更多的功能。)
至于为什么缺少所有这些功能,他们根本没有时间填补早期版本中的空白。