文件系统树的打印元素

问题描述 投票:0回答:1

我有这棵树:

type filename = string
type content = Bytes.t

type fs = 
  | FileContent of content 
  | Folder of (filename * fs) list

let f1 = FileContent(Bytes.of_string "poum")
let f2 = FileContent(Bytes.of_string "think")
let f3 = Folder [("f1.mp3", f1); ("f2.mp3", f2)]
let f4 = FileContent (Bytes.of_string "text")
let f5 = Folder [("my music", f3); ("t.txt", f4)]

我想用这个签名写一个函数

iter
fs -> unit
这样
iter f
打印
f
中元素的名称并递归地将调用应用于它的元素。首选顺序并不重要。

预期输出为:

my music
f1.mp3
f2.mp3
t.txt

我是这样开始的:

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> ...
  | Folder [] -> ()

我的问题是我可以递归调用

f1
等等,但是如何为列表做这件事呢?另外
Stdlib.Printf.printf c
c
下显示红色错误波浪线。

更新

以不同的方式,我想要一个

travaerse func f
函数(签名:
(content -> content option) -> fs -> fs
),这样
traverse
返回与
f
相同的结构,其中叶子
e = content
可以根据值进行修改
func e
,如果这个值是
None
我们保留
e
,否则我们返回返回的选项的值。基于上述问题的解决方案,我尝试这样做:

let rec traverse func f = 
  match f with
  | FileContent c -> 
    begin
      match func c with
      | Some e -> FileContent e
      | None -> FileContent c
    end
  | Folder ((n, f1)::t) -> 
    traverse func f1;
    traverse func @@ Folder t
  | Folder [] -> Folder []

但问题是如何在

fs
内返回结构
Folder ((n, f1)::t) ->

functional-programming tree ocaml
1个回答
1
投票

所以你给了我们这个开始,这表明我们显然不关心打印文件内容。

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> ...
  | Folder [] -> ()

首先,您需要打印文件名。这很简单:

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> 
    print_endline n
  | Folder [] -> ()

但是没有递归,所以打印第一个文件名然后停止。接下来让我们递归地打印文件内容。

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> 
    print_endline n;
    iter f1
  | Folder [] -> ()

但是我们用

t
做什么呢?好吧,我们用 iter 递归打印它。

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> 
    print_endline n;
    iter f1;
    iter t
  | Folder [] -> ()

嗯,现在这不能编译,因为

iter
需要一个
fs
值,而不是一个列表,这就是它。如果我们认为
Folder
包装一个列表,那么解决方案是将这个列表重新包装为一个文件夹。

let rec iter f = 
  match f with
  | FileContent c -> ()
  | Folder ((n, f1)::t) -> 
    print_endline n;
    iter f1;
    iter @@ Folder t
  | Folder [] -> ()

现在,认识到实际的文件内容并不重要,我们可以稍微简化一下:

let rec iter f =
  match f with
  | FileContent _ | Folder [] -> ()
  | Folder ((n, f1)::t) ->
    print_endline n;
    iter f1;
    iter @@ Folder t
© www.soinside.com 2019 - 2024. All rights reserved.