将字符串列表的每个元素作为字符串在其自己的行上输出 - sml
Outputting each element of a string list on its own line as a string - sml
我是 SML 的新手,至少可以说这很令人沮丧。
我使用一种数据类型,我将其称为条目
datatype entry =
File of string
| Directory of string * contents
withtype contents = entry list
帮我创建一个像这样的文件目录的复合模式
val files =
Directory("d1",
[ File "f1",
Directory("d2",
[ File "f2",
Directory("d3",[File "f3"])
]),
File "f4",
Directory("d3",[File "f5"])
]);
我想创建相互递归的函数(我刚学到的东西),它将文件中的每个条目打印在它自己的行上。基本上有这样的输出:
d1
f1
...
f5
我试过这个:
fun print_entries (File s) = [s] (* I've even tried s^"\n" but that only gets me "f#\n" for each file *)
| print_entries (Directory(s, contents)) = s::(print_contents contents)
and
print_contents nil = nil
| print_contents (e::es) = print_entries e @ (print_contents es)
但它只输出条目列表。感谢您提供的所有帮助。
您的 print_entries
/print_contents
函数当前生成一个列表,可以轻松打印:
fun print_line s = (print s; print "\n")
List.app print_line (print_entries files)
否则,您可以重新定义它以直接打印文件:
fun print_entries (File s) = print_line s
| print_entries (Directory(s, contents)) = (print_line s; print_contents contents)
and print_contents [] = ()
| print_contents (e::es) = (print_entries e; print_contents es)
结构相同,但不是使用::
和@
递归构造列表,而是使用命令式命令(print
)和排序(;
).
小提示:entry
的定义中不需要使用withtype
:
datatype entry =
File of string
| Directory of string * entry list
鉴于您的条目类型,
datatype entry = File of string | Directory of string * entry list
您可以通过相互递归生成 file/directory 个名称的列表,
fun names (File name) = [name]
| names (Directory (name, entries)) = name :: names_entries entries
and names_entries [] = []
| names_entries (entry :: entries) = names entry @ names_entries entries
或者您可以使用 List.map
:
来处理列表 entries
fun names (File name) = [name]
| names (Directory (name, entries)) =
name :: List.concat (List.map names entries))
由于 List.map
对 names <entry>
的每次调用都会生成一个名称列表,因此 List.map names entries
会生成一个包含 个 名称列表的列表。使用 List.concat
.
将其展平为单个名称列表
这有点像相互递归,但是 entry
和 entry list
之间的相互依赖嵌入在传递给 List.map
的 names
函数和列表递归中由 List.map
单独处理。
您还可以通过折叠文件条目来获取姓名列表:
fun cata f acc entry =
case entry of
File name => f (entry, acc)
| Directory (name, entries) =>
let val acc' = f (entry, acc) in
foldl (fn (entry, acc'') => cata f acc'' entry) acc'
end
fun name (File name) = name
| name (Directory (name, _)) = name
val names =
rev o cata (fn (entry, names) => name entry :: names) []
此功能对其他事情很有用,例如递归计算文件和目录的数量:
fun isFile (File _) = true
| isFile (Directory _) = false
fun isDirectory (Directory _) = true
| isDirectory (File _) = false
val countFilesDirectories =
let fun counter (entry, (numFiles, numDirs)) =
if isFile entry then (numFiles+1, numDirs) else
if isDirectory entry then (numFiles, numDirs+1) else
(numFiles, numDirs)
in cata counter (0,0) end
甚至递归打印文件名和目录名:
val printEntries =
cata (fn (entry, ()) => print (name entry ^ "\n")) ()
我是 SML 的新手,至少可以说这很令人沮丧。
我使用一种数据类型,我将其称为条目
datatype entry =
File of string
| Directory of string * contents
withtype contents = entry list
帮我创建一个像这样的文件目录的复合模式
val files =
Directory("d1",
[ File "f1",
Directory("d2",
[ File "f2",
Directory("d3",[File "f3"])
]),
File "f4",
Directory("d3",[File "f5"])
]);
我想创建相互递归的函数(我刚学到的东西),它将文件中的每个条目打印在它自己的行上。基本上有这样的输出:
d1 f1 ... f5
我试过这个:
fun print_entries (File s) = [s] (* I've even tried s^"\n" but that only gets me "f#\n" for each file *)
| print_entries (Directory(s, contents)) = s::(print_contents contents)
and
print_contents nil = nil
| print_contents (e::es) = print_entries e @ (print_contents es)
但它只输出条目列表。感谢您提供的所有帮助。
您的 print_entries
/print_contents
函数当前生成一个列表,可以轻松打印:
fun print_line s = (print s; print "\n")
List.app print_line (print_entries files)
否则,您可以重新定义它以直接打印文件:
fun print_entries (File s) = print_line s
| print_entries (Directory(s, contents)) = (print_line s; print_contents contents)
and print_contents [] = ()
| print_contents (e::es) = (print_entries e; print_contents es)
结构相同,但不是使用::
和@
递归构造列表,而是使用命令式命令(print
)和排序(;
).
小提示:entry
的定义中不需要使用withtype
:
datatype entry =
File of string
| Directory of string * entry list
鉴于您的条目类型,
datatype entry = File of string | Directory of string * entry list
您可以通过相互递归生成 file/directory 个名称的列表,
fun names (File name) = [name]
| names (Directory (name, entries)) = name :: names_entries entries
and names_entries [] = []
| names_entries (entry :: entries) = names entry @ names_entries entries
或者您可以使用 List.map
:
entries
fun names (File name) = [name]
| names (Directory (name, entries)) =
name :: List.concat (List.map names entries))
由于 List.map
对 names <entry>
的每次调用都会生成一个名称列表,因此 List.map names entries
会生成一个包含 个 名称列表的列表。使用 List.concat
.
这有点像相互递归,但是 entry
和 entry list
之间的相互依赖嵌入在传递给 List.map
的 names
函数和列表递归中由 List.map
单独处理。
您还可以通过折叠文件条目来获取姓名列表:
fun cata f acc entry =
case entry of
File name => f (entry, acc)
| Directory (name, entries) =>
let val acc' = f (entry, acc) in
foldl (fn (entry, acc'') => cata f acc'' entry) acc'
end
fun name (File name) = name
| name (Directory (name, _)) = name
val names =
rev o cata (fn (entry, names) => name entry :: names) []
此功能对其他事情很有用,例如递归计算文件和目录的数量:
fun isFile (File _) = true
| isFile (Directory _) = false
fun isDirectory (Directory _) = true
| isDirectory (File _) = false
val countFilesDirectories =
let fun counter (entry, (numFiles, numDirs)) =
if isFile entry then (numFiles+1, numDirs) else
if isDirectory entry then (numFiles, numDirs+1) else
(numFiles, numDirs)
in cata counter (0,0) end
甚至递归打印文件名和目录名:
val printEntries =
cata (fn (entry, ()) => print (name entry ^ "\n")) ()