F#函数使用相互递归的辅助函数

时间:2018-11-02 15:48:04

标签: f#

 type Title    = string
 type Document = Title * Element list
 and  Element  = Par of string | Sec of Document;;

 let s1   = ("Background", [Par "Bla"])
 let s21  = ("Expressions", [Sec("Arithmetical Expressions", [Par "Bla"]);
                             Sec("Boolean Expressions", [Par "Bla"])])
 let s222 = ("Switch statements", [Par "Bla"])
 let s223 = ("Repeat statements", [Par "Bla"])
 let s22  = ("Statements",[Sec("Basics", [Par "Bla"]) ; Sec s222; Sec s223])
 let s23  = ("Programs", [Par "Bla"])
 let s2   = ("The Programming Language", [Sec s21; Sec s22; Sec s23])
 let s3   = ("Tasks", [Sec("Frontend", [Par "Bla"]);
                       Sec("Backend", [Par "Bla"])])
 let doc  = ("Compiler project", [Par "Bla"; Sec s1; Sec s2; Sec s3]);;

定义一个F#函数toc: Document → ToC,该函数为文档生成目录。例如,该文档的前缀应带有编号的副标题,如下所示:

[([], "Compiler project");
     ([1], "Background");
     ([2], "The Programming Language");
     ([2;1], "Expressions");
     ([2;1;1], "Arithmetical Expressions");
     ([2;1;2], "Boolean Expressions");
     ([2;2], "Statements");
     ([2;2;1], "Basics");
     ([2;2;2], "Switch statements");
     ([2;2;3], "Repeat statements");
     ([2;3], "Programs");
     ([3], "Tasks");
     ([3;1], "Frontend");
     ([3;2], "Backend")]

2 个答案:

答案 0 :(得分:0)

您的问题似乎遗漏了很多。例如:您认为哪些相互递归的辅助函数会对此有所帮助?

在我看来,这应该很简单,因为它只有一个递归函数。基本逻辑可以是:

  1. 对于每个元素,如果它是一个段落,请忽略它,或者如果它是一个子节,则生成相应的目录。
  2. 将一个新索引(每个小节一个,从1开始)附加到每个小节中的所有条目。
  3. 在此目录的开头添加[],title

答案 1 :(得分:0)

您可以通过在序列表达式中遍历各节,保留当前节的编号并产生具有当前节号的所有标题来相对容易地做到这一点。

// Given the current level (as a list of numbers) and a list of elements, 
// generate a list of headings in the elements and prepend `idx` indices
// to each heading that we generate
let rec generateToc idx elems = seq {

  // We only care about nested sections, so this gets a list containing
  // just sections and we later add number to them using `Seq.indexed`
  let nested = elems |> Seq.choose (function 
    | Sec(title, elems) -> Some(title, elems) | _ -> None) 

  // For every nested section, we yield the title of the section and then
  // recursively call `generateToc` to get the nested section titles
  // (we append the current section number to `idx` when making the recursive call)
  for i, (title, elems) in Seq.indexed nested do
    yield List.rev (i+1::idx), title
    yield! generateToc (i+1::idx) elems }

// To generate document TOC, we just yield the document title and
// then call `generateToc` on the document elements
let generateDocToc (title, elems) = seq {
  yield [], title
  yield! generateToc [] elems }

generateDocToc  doc
|> Seq.iter (printfn "%A")