我来自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;)?
答案 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") ] ]