【问题标题】:How to get out of this infinite loop in SML如何摆脱 SML 中的这个无限循环
【发布时间】:2021-03-17 21:37:52
【问题描述】:

这是我的代码现在的样子。

我正在尝试制作一个多选题程序

这是一种非常初级的处理方式,但我发现很难以更“专业”的方式构建代码。

fun readlist(filename) =
    let 
        val file = TextIO.openIn filename
        val text = TextIO.inputAll file
        val _ = TextIO.closeIn file
    in
        String.tokens (fn c => c = #"\n") text
    end;
  
(*Get user answer from keybord*)
fun getAnswer() = (
    print "\nPlease enter your answer. Options(case sensitive): \nA-) \tB-) \tC-) \tD-)\n";
    let
        val return = valOf (TextIO.inputLine TextIO.stdIn)
    in
        return
    end
);
    
(*Verify if the choosen line is a new starting question block base on fact that each question block contains 7 line*)
fun getQuestionLine(t) = 
    case t of 
    [] => []
    |t::ts => if t mod 7 = 0 then
        t::getQuestionLine(ts)
     else
        getQuestionLine(ts);

fun toIntList(x:int) = x;
val getblockStarts = getQuestionLine(List.tabulate(List.length(readlist("questionBank.txt")), toIntList));
fun member (x, []) = false
    | member (x, y::yt) = x = y orelse member (x, yt);

fun seed () =
    let
        val aReal = Time.toReal(Time.now()) - 1.0e9
        val floorReal = Real.realFloor(aReal)
        val dec = aReal - floorReal
        val sd1 = Real.floor(dec);
        val sd2 = Real.floor(1000.0 * dec);
    in
        Random.rand(sd1,sd2)
    end;

fun randList (N) =
    let
      fun subfun (N, i) intList =
          if N = 0 then intList
          else
              let
                  val tmp = Random.randRange(1, (List.length(readlist("questionBank.txt"))))
                  val randVal = tmp i
              in
                  if member(randVal, getblockStarts) then
                      subfun (N - 1, i) (randVal :: intList)
                  else
                      subfun (N, i) intList
              end;
    in
        subfun (N, seed()) []
    end;

fun ask(questionIndexList) =
    let
      fun loop (n) =
          let
              val question = print(
                  "\n"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1))^"\n\t"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+1)^"\n\t"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+2)^"\n\t"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+3)^"\n\t"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+4)^"\n\t"^
                  List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+5)^"\n"
              )
              val userAns = getAnswer()
          in
              if userAns = List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+6)^"\n" then
                (
                  print("Your answer is CORRECT.\n");
                  loop (List.length(List.take(questionIndexList, List.length(questionIndexList)-1)))
                )
              else (
                  print(
                      "Your answer is INCORRECT.\nThe correct answer is: "^
                      List.nth(readlist("questionBank.txt"), List.nth(questionIndexList, n-1)+6)
                      ^"\n\n"
                  );
                  loop (List.length(List.take(questionIndexList, List.length(questionIndexList)-1)))
                )
          end
    in
        loop (List.length(questionIndexList))
    end;

ask(randList(3));

我从我的问题文件中添加了一个捕获。

所有问题都遵循这种格式

我的代码按我想要的方式运行,但循环的最后一圈是无止境的。控制台为我提供了三个我回答的问题,如果我没有找到它,我有正确的答案,但是第三个问题被一遍又一遍地问到没有结束。

我一直在寻找所有地方,但我不知道我的错误在哪里。我需要帮助才能摆脱这个循环。

【问题讨论】:

    标签: loops infinite-loop sml smlnj


    【解决方案1】:

    我将ask 函数更改为使用要提问的问题数量,而不是要显示的问题块列表。

    fun ask(n) =
        let
          fun loop (n) =
              let
                  val newQues = randList(1)
                  val question = print(
                      "\n"^
                      List.nth(readlist("questionBank.txt"), hd newQues)^"\n\t"^
                      List.nth(readlist("questionBank.txt"), (hd newQues)+1)^"\n\t"^
                      List.nth(readlist("questionBank.txt"), (hd newQues)+2)^"\n\t"^
                      List.nth(readlist("questionBank.txt"), (hd newQues)+3)^"\n\t"^
                      List.nth(readlist("questionBank.txt"), (hd newQues)+4)^"\n\t"^
                      List.nth(readlist("questionBank.txt"), (hd newQues)+5)^"\n"
                  )
                  val userAns = getAnswer()
              in
                  if userAns = List.nth(readlist("questionBank.txt"), (hd newQues)+6)^"\n" then
                    (
                      print("Your answer is CORRECT.\n");
                      if n > 1 then loop (n-1) else ()
                    )
                  else (
                      print(
                          "Your answer is INCORRECT.\nThe correct answer is: "^
                          List.nth(readlist("questionBank.txt"), (hd newQues)+6)
                          ^"\n\n"
                      );
                      if n > 1 then loop (n-1) else ()
                    )
              end
        in
            loop (n)
        end;
    
    ask(5);
    

    所以它现在可以按我的意愿工作了。

    如果有人有优化的想法,我很乐意阅读。

    【讨论】:

      【解决方案2】:

      没有条件带你离开loop;你在两个条件分支中无条件递归。

      如果不是因为这个事实,你可以通过检查零来解决这个问题

      List.length(List.take(questionIndexList, List.length(questionIndexList)-1))
      

      总是相同的数字。
      (即List.length(questionIndexList)-1——如果从列表中取出 K 个元素,则结果的长度为 K。无需创建列表来确定其长度。)

      但我会采用不同的结构。

      每次需要问题时,您都在阅读该文件。
      最好读取一次文件并传递列表。

      首先,一个代表问题和答案的类型:

      type Options = string * string * string * string;
      datatype QA = QA of string * Options * string;
      

      还有几个函数可以从笨重的字符串列表中收集它们:

      fun toQAs [] = []
        | toQAs (q::o1::o2::o3::o4::a::qas) = (QA (q, (o1,o2,o3,o4), a)) :: (toQAs qas);
      
      fun readQuestions file = toQAs (readlist file);
      

      还有一个打印问题的实用函数:

      fun printQuestion (QA (q, (o1,o2,o3,o4), _)) = print ("\n"^ q^"\n\t"^ o1^"\n\t"^ o2^"\n\t"^ o3^"\n\t"^ o4^"\n");
      

      ask 函数只接受一个问题列表并询问所有问题:

      fun ask [] = print "No further questions.\n"
        | ask  (q::qs) =
          let val (QA (_, _, answer)) = q
          in
              printQuestion q;
              if getAnswer() = answer^"\n" then
                   print "Your answer is CORRECT.\n"
               else
                   print ("Your answer is INCORRECT.\nThe correct answer is: "^ answer ^"\n\n");
              ask qs
          end;
      

      最后,一个函数根据文件创建随机问题列表,并提出问题:

      fun go () =
          let
              val QAs = readQuestions "questionBank.txt"
          in
              ask (map (fn i => List.nth(QAs, i)) (randList (length QAs) 3))
          end;
      

      【讨论】:

      • @PeterSmith 我更改了我的代码以便能够使用您的建议但最后我有这个错误:test1.sml:88.46-88.69 错误:运算符不是函数 [tycon mismatch] 运算符:表达式中的 int 列表:(randList (length QAs)) 3
      • @PeterSmith 我也想知道如果我想根据每个问题属于一个类别的假设来按类别计算正确答案的百分比,我该怎么做?我曾经以一种方式做到这一点,但对于数据类型,我认为它会有点难以处理
      • @IndifineGenome “彼得·史密斯”是谁?首先,你犯了一个括号错误。使用复制和粘贴(这是从测试代码中复制和粘贴的)。其次,向问题类型添加“类别”非常容易。例如,您可以从ask 返回正确和错误回答的问题,然后计算统计数据。
      • 抱歉打错了???
      猜你喜欢
      • 2019-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多