【问题标题】:Write command-line arguments to file将命令行参数写入文件
【发布时间】:2018-10-14 17:35:38
【问题描述】:

我在完成这项任务时遇到了麻烦。我们应该将命令行参数作为输入并将它们写入文件。 到目前为止,我已经完成了以下代码:

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

【问题讨论】:

    标签: command-line arguments sml smlnj


    【解决方案1】:

    这有点重复以下两个问答:

    以下是一些一般性反馈:

    • 缩进:您可以通过添加缩进使代码更具可读性。

      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 听起来像 operating system,而它可能是 outstream 的缩写。就叫它outstream。有些人喜欢称它为fd 来表示文件描述符,但这完全取决于目标受众的理解。 args 可能更通用:此函数可以编写任何字符串列表,而不仅仅是命令行参数。就叫它linesa 听起来可以是任何类型,但它只是一个整数。我称之为n,但实际上我不会使用数字来确定我的停止条件。

    • 分号:当您的函数执行多项具有副作用的操作时,您可以使用; 运算符。您没有在 then 部分中执行此操作,并且您在 else 部分中做错了,诚然因为 SML 中的 ; 运算符是 @ 987654323@confusing.

      简短版:val foo = x; val bar = y; 中的分号与val foo = (TextIO.output (fd, x); TextIO.output (fd, y)) 中的分号不同。

      如果您需要分号 表达式 运算符,请将分号表达式包含在括号或 let 表达式中。否则,它将被解释为(可选)分号 declaration 运算符。

    • 在迭代行列表时,而不是保留计数器,对列表执行模式匹配。这极大地简化了您的递归结束时,因为无论如何您总是一次处理一个列表的头部。

    • 不要退出:您可能不想在完成后退出程序;退出该功能就足够了。这样,您可以在更复杂的控制流中重复使用该函数,而无需代表整个程序退出。

    • 在同一范围内打开和关闭文件:这是一般的编程建议:当您处理副作用时,确保您不会忘记关闭您想要的东西' 已经打开并且您不会关闭两次,在代码的同一附近执行此操作会使您更容易推理正确性。你可以发a simple function that always deals with the opening and closing

    • 函数体内部的val当您需要在函数体或某个表达式内进行临时值绑定时,请使用let-表达式。顺便说一句,今天有人问Why do I use `let` and not just `val` to declare a variable inside a function in SML?

    • 不可变值:在 SML 中,您不能更新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
    

    val _ = ...s 是在顶层评估表达式的一种奇特方式,而无需直接在顶层使用表达式。在交互式 REPL 中,foo(); 在其自己的行中表示 val it = foo();,但是一旦你编译你的程序来生成独立的二进制可执行文件,这将不再有效。val _ = ... 在执行后基本上会丢弃计算结果,并且由于writeFileTextIO.closeOut 都返回(),它们'不值得绑定任何东西。)

    【讨论】:

    • 哇,非常感谢。对不起。在使用 Stack Overflow 大约 6 年的时间里,这是我提出的第一个问题。我会记住所有这些要点。通过您的更正,它现在在您修改的代码的第 3 行给了我一个“错误:语法错误:插入 RPAREN”。我搜索了堆栈溢出,似乎找不到这个错误的解释。抱怨的错误是什么?
    • 哦,负数的整数文字是~1,而不是-1
    猜你喜欢
    • 2018-04-18
    • 1970-01-01
    • 2012-02-18
    • 2014-03-10
    • 2017-08-20
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多