F#中的文件系统实现

时间:2014-10-11 03:16:05

标签: f#

我来自C#背景,刚刚开始学习F#。 我似乎被困在一项看似相当简单的任务上。

我需要使用GIVEN(更改它不是一个选项)类型来实现文件系统,其中' a用于名称,&b; b用于数据。

type Tree<'a,'b> = Node of list<'a * Tree<'a,'b>>
                 | Leaf of 'b

然后,文件系统将成为此类型的实例,其中文件/目录名称由字符串&#39; a提供,文件内容由字符串&#39; b提供。目录应该是节点和文件离开。

type FileSystem = Tree<string,string>

// / (directory)
// /home (directory)
// /home/.emacs (file)
// /home/.ssh (directory)
// /home/.ssh/id_rsa (file)
// /usr  (directory)
// /usr/bin (directory)
// /usr/bin/bash (file)
// /usr/bin/emacs (file)

我被困在......

let fs = Node["/",
             Node["home",
                 Node[".ssh",
                     Node["id_rsa", Leaf("id_rsa_DATA")]
                     ]  
                 ]
              ]

任何尝试向任何节点添加更多节点或叶子都会失败,因为编译器需要树而不是列表? 构建这样的树的正确语法是什么?

使用这棵树我需要实现:

ls : FileSystem -> list<string>  // list root directory
subfs : FileSystem -> list<string> -> FileSystem // return the filesystem you find at that path
ls' : FileSystem -> list<string> -> list<string> // list data of directory files at given path (fail if its just a file)

编辑:

所以就是这样:

let fs = Node["/", 
              Node["home/",
                    Node[".ssh/",
                         Node["id_rsa", Leaf("id_rsa_DATA")
                             ];
                   ".emacs", Leaf(".emacs_DATA")
                   ];
                   "usr/",
                    Node["bin/",
                          Node["bash", Leaf("bash_DATA");
                               "emacs", Leaf("emacs_DATA")
                              ];
                   ".emacs", Leaf(".emacs_DATA")];
                  ]
             ]

现在如何列出目录和子文件系统(ls,subfs,ls&#39;)?

2 个答案:

答案 0 :(得分:1)

这更接近你想要的吗?

也就是说,每个节点都是某个值'a的元组和一个Tree&lt;'a,'b&gt;类型的子项列表?

type Tree<'a,'b> = 
  | Node of 'a * Tree<'a,'b> list
  | Leaf of 'b

let fs = Node("/",
               [Node("home",
                       [Node(".ssh",
                               [Node("id_rsa", 
                                  [Leaf("id_rsa_DATA")]
                               )]
                       )]
               )]
             )

let rec f n =
  match n with
  | Node(".ssh",nodeList)::tail -> 
      printfn "found .ssh"
      f tail
      f nodeList
  | Leaf(leafStr)::tail -> 
      printfn "found leaf %s" leafStr
      f tail

f [fs]

这种结构的递归情况比使用它要复杂得多,所以......你可能更喜欢这个定义:

type Tree<'a,'b> = 
  | Node of 'a * Tree<'a,'b> list
  // omit the leaf and define it as a node with an empty list of children

除非您当然希望更明确地了解您的工作内容:

type FileSys<'a,'b> = 
  | Folder of 'a * FileSys<'a,'b> list
  | File of 'b

如果我们谈论的是文件和文件夹标签系统,它是否需要通用?

type FileSys = 
  | Folder of string * FileSys list
  | File of string

通常采用优先于通用类型的歧视联盟的解决方案是更简单的方法。如果你这样做,你就会更加信任FSharp丰富的结构和模式匹配,而不是首先建立一套通用的工具,以便随后可以解决你的问题。使用F#推理并围绕您的问题制作工具空间可以同时以探索的方式发生。

答案 1 :(得分:1)

您需要列出元素('a * Tree<'a,'b>)为目录(或子目录)的string * Node,以及文件的string * Leaf

这样你就会得到这样的结果:

type Tree<'a,'b> = 
    | Node of list<'a * Tree<'a,'b>>
    | Leaf of 'b

let fs = Node["/", 
               Node ["someFile.txt", Leaf("content");
                     "aFile.txt", Leaf("some content");
                     "someDir/",
                       Node [ "anotherFile.txt", Leaf("more content");
                              "script.sh", Leaf("script content")      ];
                     "logfile.log", Leaf("log content") ] ]