3

在我尝试转换为 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
        }

我想知道如何将带有yield的seq{...} 表达式转换为 OCaml?我的第一个猜测是seq必须成为一个列表。

4

3 回答 3

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还有多余的括号。

于 2013-01-20T19:44:07.353 回答
3

我会说这seq是一个惰性列表,即在需要时计算其尾部而不是一次计算的列表。OCaml 中最接近的东西可能是流解析器,它是可通过 camlp4 获得的扩展。它记录在 OCaml 手册的语言扩展部分。

您还可以创建自己的显式惰性列表工具,fun () -> expr用于表示列表的尾部。

如果您的列表相当小,您也可以按照您的建议转换为普通列表。

于 2013-01-20T19:42:57.197 回答
2

我会看看LazyList.from电池: http: //ocaml-batteries-team.github.com/batteries-included/hdoc2/BatLazyList.html

但是,我认为它不会像您的解决方案那样方便。

于 2013-01-20T19:55:32.577 回答