在我试图转换为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
| (y, z) -> yield (y, z)
yield! parseList (List.tail lst) z
}
我想知道如何将 seq {...} 表达式与 yield 转换为OCaml?我的第一个猜测是 seq 必须成为一个列表。
答案 0 :(得分:5)
最简单的翻译(不是尾递归)是:
let rec parseList lst off =
match lst with
| [] -> []
| x::xs ->
match parse off x with
| Unmatched, _ as y -> [y]
| y, z -> (y, z)::parseList xs z
尾递归版是:
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
的调用是不必要的潜在异常来源。并且有多余的括号。
答案 1 :(得分:3)
我会说seq
是一个惰性列表,即一个列表,其尾部是在需要时计算的,而不是一次性计算的。 OCaml中最接近的东西可能是流解析器,可通过camlp4获得扩展。它记录在OCaml手册的Language Extensions部分中。
您还可以使用fun () -> expr
创建自己的显式懒惰列表工具,以表示列表的尾部。
如果您的列表相当小,您也可以按照建议转换为普通列表。
答案 2 :(得分:2)
我会看一下电池中的LazyList.from
:http://ocaml-batteries-team.github.com/batteries-included/hdoc2/BatLazyList.html
但是,我认为它不如您的解决方案那么方便。