将字符串列表中的每个元素作为string-sml输出到它自己的行上

将字符串列表中的每个元素作为string-sml输出到它自己的行上,sml,smlnj,ml,Sml,Smlnj,Ml,我是SML的新手,至少可以说我觉得很沮丧 我使用了一个数据类型,我称之为entry datatype entry = File of string | Directory of string * contents withtype contents = entry list 帮助我创建一个文件目录的复合模式,如下所示 val files = Directory("d1", [ File "f1", Directory("d2", [ File

我是SML的新手,至少可以说我觉得很沮丧

我使用了一个数据类型,我称之为entry

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"])
    ]);
我想创建相互递归的函数(我刚刚学到的东西),它将在文件中的每一个条目都打印在自己的行上。基本上具有如下输出:

我试过这个:

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\u条目
/
print\u内容
功能当前生成一个列表,可以轻松打印:

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
)和排序(

一个小提示:在
条目
的定义中,不需要使用
with type

datatype entry =
  File of string
| Directory of string * entry list
考虑到你的参赛类型

datatype entry = File of string | Directory of string * entry list
您可以通过相互递归生成文件/目录名列表

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
来处理列表
条目

fun names (File name) = [name]
  | names (Directory (name, entries)) =
      name :: List.concat (List.map names entries))
由于由
List.map
执行的对
names
的每次调用都会生成一个名称列表,
List.map names条目
会生成一个名称列表。使用
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")) ()
甚至可以递归打印文件名和目录名:

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")) ()

谢谢你的帮助!对不起,除了这项任务外,我还有其他一些任务要做。