将F#seq表达式转换为OCaml
在我试图转换为OCaml的F#代码中,我遇到了以下问题:将F#seq表达式转换为OCaml,f#,ocaml,F#,Ocaml,在我试图转换为OCaml的F#代码中,我遇到了以下问题: let rec parseList lst off = seq { if List.isEmpty lst then () else match parse off <| List.head lst with | (Unmatched, _) as y -> yield y
let rec parseList lst off =
seq {
if List.isEmpty lst then ()
else
match parse off <| List.head lst with
| (Unmatched, _) as y -> yield y
| (y, z) -> yield (y, z)
yield! parseList (List.tail lst) z
}
让rec parseList lst关闭=
序号{
如果List.isEmpty lst,则()
其他的
匹配
|(y,z)->收益率(y,z)
yield!parseList(List.tail lst)z
}
我想知道如何将seq{…}表达式和yield转换成OCaml?我的第一个猜测是,seq必须成为一个列表。我想说
seq
是一个懒惰的列表,也就是说,它的尾部是在需要时计算出来的,而不是一次全部计算出来的。OCaml中最接近的东西可能是流解析器,它是通过camlp4提供的扩展。它在OCaml手册的章节中有记录
您还可以使用fun()->expr
创建自己的显式惰性列表工具来表示列表的尾部
如果您的列表相当小,也可以按照您的建议转换为普通列表。最简单的翻译(不是尾部递归)是:
尾部递归版本为:
let parseList lst off =
let rec loop xs off = function
| [] -> xs
| y::ys ->
match parse off y with
| Unmatched, _ as x -> x::xs
| _, z as x -> loop (x::xs) z ys in
List.rev (loop [] off lst)
请注意,您开始使用的F#代码还有很多需要改进的地方。调用
List.head
和List.tail
是不必要的潜在异常源,您可以更轻松地使用模式匹配。还有多余的括号。我想看一看《懒人名单》。从《电池》中的:
但是,我认为它不会像您的解决方案那样方便。根据您使用结果的方式(即序列的元素),您可能能够使用OCaml模块。实际上,我正在翻译的F代码创建了这个seq,然后立即将其转换成一个列表,所以我猜使用Stream比一开始创建列表没有什么好处?@GuyCoder只需搜索带有F和OCaml标记的问题:我对你链接的文档有点困惑。它说在OCAML3.03中删除了流,但您可以使用campl4语法扩展。然后还讨论了流模块。流模块是否使用camlp4语法扩展,或者它只是处理流的一个完全独立的选项?如果是后者,那么与流模块相比,使用camlp4语法扩展有什么好处?camlp4支持的流有很好的语法。我从未尝试过,但我相信您可以在没有语法的情况下单独使用流模块。
seq
可以在每次枚举之前和之后执行代码(例如,创建和销毁数据库连接)。seq
使用可变枚举数。惰性列表由thunk组成,在强制计算时,这些thunk会变异为值,因此元素会从一个枚举记到下一个枚举,而seq
则会在每次枚举时重新计算。这似乎是最简单的方法。由于F#创建了一个seq,然后立即将该seq转换为一个列表,我想使用LazyList或Stream模块并没有什么好处。“注意,您开始使用的F#代码还有很多需要改进的地方。”+1仅此一项。
let parseList lst off =
let rec loop xs off = function
| [] -> xs
| y::ys ->
match parse off y with
| Unmatched, _ as x -> x::xs
| _, z as x -> loop (x::xs) z ys in
List.rev (loop [] off lst)