我在完成这项任务时遇到了麻烦。我们应该将命令行参数作为输入并将它们写入文件。 到目前为止,我已经完成了以下代码:
val args = CommandLine.arguments()
val a = length args;
val os = TextIO.openOut "rodr4719.txt";
TextIO.output(os, "rodr4719");
fun writeFile(os, args, a) =
if a = -1 then
TextIO.output(os, "rodr4719")
TextIO.closeOut os
OS.Process.exit(OS.Process.success)
else
val str = nth (args, a);
TextIO.output(os, str ^"\n" );
a = a-1;
writeFile(os, args, a)
end;
writeFile(os, args, a-1)
我得到的错误是
.sml:22.1 Error: syntax error: inserting EQUALOP
答案 0 :(得分:0)
这有点与以下两个Q& A的重复:
以下是一些一般性反馈:
缩进:您可以通过添加缩进来使代码更具可读性。
fun writeFile (os, args, a) =
if a = -1 then
TextIO.output(os, "rodr4719")
TextIO.closeOut os
OS.Process.exit(OS.Process.success)
else
val str = nth (args, a);
TextIO.output(os, str ^"\n" );
a = a-1;
writeFile(os, args, a)
end
(由于以下列举的原因,此代码仍然存在。)
end
:当您宣布fun
时,不需要此关键字。它出现在SML语法的几个地方,特别是let ... in ... end
,你可能已经在那里看到了它。
变量名称:我以不同的方式命名输入参数:os
听起来像操作系统,当它可能是缩写时 outstream 。只需将其称为outstream
即可。有些人喜欢将其称为fd
以获取文件描述符,但这完全取决于对目标受众的理解。 args
可能更通用:此函数可以编写任何字符串列表,而不仅仅是命令行参数。只需将其称为lines
即可。 a
听起来可能是任何类型,但它只是一个整数。我将其称为n
,但我实际上并未使用数字来确定我的停止条件。
分号:当您的函数使用副作用执行多项操作时,您可以使用;
运算符。您在然后 -part中没有这样做,并且您在 else -part中做错了,因为{{1} SML中的}运算符是syntactically confusing。
简短版本:;
中的分号与val foo = x; val bar = y;
中的分号不同。
如果需要分号表达式运算符,请将分号的表达式包装在括号或let-expression中。否则,它将被解释为(可选)分号声明运算符。
当迭代行列表而不是保留计数器时,在列表上执行模式匹配。这大大简化了递归结束的时间,因为无论如何,您总是一次只能找到一个列表的头部。
不要退出:您可能不想在完成后退出该计划;退出该功能应该足够了。这样,您可以在更复杂的控制流中重复使用该功能,而无需代表整个程序退出。
打开和关闭相同范围内的文件:这是一般编程建议:当您处理副作用时,确保您不会忘记关闭你打开的东西并且你不会关闭某些东西两次,在相同的代码附近做这件事会让你更容易推理出正确性。你可以a simple function that always deals with the opening and closing。
val foo = (TextIO.output (fd, x); TextIO.output (fd, y))
在函数体内:当您需要在函数体或某个表达式中绑定临时值时,请使用val
- 表达式。顺便说一句,今天有人问过Why do I use `let` and not just `val` to declare a variable inside a function in SML?。
不可变的值:在SML中,您无法更新类似let
的值。 a = a-1
不是变量,而是值绑定。您可以将其重新绑定到基于旧值的新值,从而遮蔽旧值,但这不是必需的。而是使用更新后的值执行递归调用。
我已经考虑到这些事情修改了你的程序:
a
(fun writeFile (outstream, []) = ()
| writeFile (outstream, line::lines) =
( TextIO.output (outstream, line ^ "\n") ; writeFile (outstream, lines) )
(* Demo *)
val myFile = TextIO.openOut "rodr4719.txt"
val _ = writeFile (myFile, CommandLine.arguments ())
val _ = TextIO.closeOut myFile
是一种在顶级评估表达式而不直接在顶层表达式的奇特方式。在交互式REPL val _ = ...
中它自己的行意味着{ {1}},但是一旦你编译你的程序来生成独立的二进制可执行文件,这就不再有用了。foo();
在执行之后基本上抛弃了计算的结果,并且因为val it = foo();
和val _ = ...
返回writeFile
,他们不值得绑定任何内容。)