如何从 sml 中的文本文件中获取随机行? sml中如何制作多选题程序?

How can i get a random line from a text file in sml ? How to make a multi choice question program in sml?

我想用SML做一个选择题程序。

我有一个文本文件,其内容结构如下:

category1:Basic sml/sql
1-How many subsets does the power set of an empty set have?
A) One
B) Two
C) Three
D) Zero
Ans:A
2-What is the cardinality of the set of odd positive integers less than 10? 
A) 20 
B) 3 
C) 5 
D) 10 
Ans:C

每个类别有 5 个以上的问题

每个问题属于一个类别

每个问题有 4 个建议答案,后面是另一行的答案

我希望能够检索并向用户显示问题(随机问题)和相应的建议答案。我编写了这个函数,它允许我逐行检索文件的所有内容。但我仍然卡在如何卸载问答块上。

fun getFromFile(file_name) =
    let 
      val file = TextIO.openIn file_name
      val text = TextIO.inputAll file
      val _ = TextIO.closeIn file
    in
      String.tokens (fn c => c = #"\n") text
    end
    
val table = getFromFile("question_file.txt");

我该如何继续?是否可以检索文件的行而不先通过 table 传递它们(直接检索文本)?

I'm still stuck on how to unload a question-answer block.

How could I proceed?

找到一种方法来编码包含多个问题的多个类别,每个问题包含多个答案。一旦找到将其存储到文件(文件格式)的方法,请编写解码器。您当前的解码器是线路解码器。您可以使用线条对事物中的事物进行编码,但您也可以通过其他方式进行编码。

例如,using JSON:

[
  {
    "category": "Basic sml/sql",
    "questions": [
      {
        "question": "How many subsets does the power set of an empty set have?",
        "answers": [
          { "answer": "Zero", "correct": false },
          { "answer": "One", "correct": true },
          { "answer": "Two", "correct": false },
          { "answer": "Three", "correct": false }
        ]
      },
      ...
    ]
  },
  ...
]

如果依赖第三方库太难,你可以自己想出一种文件格式,例如基于行的:

CATEGORY Basic sml/sql
QUESTION How many subsets does the power set of an empty set have?
ANSWER Zero
ANSWER_CORRECT One
ANSWER Two
ANSWER Three
QUESTION ...

所以给定你的基于行的 reader,遍历每一行并查看第一个单词:

  1. 如果是 CATEGORY,开始一个新类别。
  2. 如果是 QUESTION,请在当前类别中开始一个新问题。
  3. 如果是 ANSWERANSWER_CORRECT,请在当前类别的当前问题中提供一个选项。

这建议采用递归函数(因为它需要遍历每一行),该函数采用多个参数:当前类别、当前问题以及到目前为止的类别、问题和答案的总集合。

此时你可能要思考:如何在内存中存储有多个答案的问题类别?我应该使用什么数据类型?例如。使用类型别名,您可以这样表达您的数据模型:

type answer_option = string * bool
val example_answer_option = ("Zero", false) : answer_option

type question_answers = string * answer_option list
val example_question_answers =
    ("How many subsets does the power set of an empty set have?",
     [
       ("Zero", false),
       ("One", true),
       ("Two", false),
       ("Three", false)
     ]
    ) : question_answers

type category = string * question_answers list
val example_category =
    ("Basic sml/sql",
     [ example_question_answers ]
    ) : category

val example_categories = [ example_category ] : category list

SML 类型别名的工作方式是将所有这些扩展为它们所包含的基本类型,因此它们可能会在您的 REPL 中显示为:

> type answer_option = string * bool
  type question_answers = string * (string * bool) list
  type category = string * (string * (string * bool) list) list

可读性差得多,这也是使用 datatypeabstype 或不透明模块等替代方法的原因之一。

但是,您可以这样定义一个存根:

fun parse (line::lines, currentQuestion, currentAnswers, currentCategory, acc) =
    case splitFirstWord line of
         ("CATEGORY", cat)          => ...
       | ("QUESTION", q)            => ...
       | ("ANSWER", aWrong)         => ...
       | ("ANSWER_CORRECT", aRight) => ...
       | _                          => raise Fail ("Unknown: " ^ line)

现在有两个子问题:

  1. splitFirstWord 实际上还不存在。

  2. 有大量当前状态的簿记。

祝你好运!

Is it possible to retrieve the lines of the file without passing them through a table first (retrieve the text directly)?

这个问题我不是很懂。毫无疑问,是吗?

如果“table”是指某种可索引的数据结构,例如列表:

只是不要在输入上调用 String.tokens (fn c => ...)

这为您提供了基本的 string

请注意 table 只是值绑定的名称。

如果您愿意,可以通过 chair 传递它:

fun getFromFile(file_name) =
    let 
      val file = TextIO.openIn file_name
      val text = TextIO.inputAll file
      val _ = TextIO.closeIn file
    in
      text
    end

val chair = getFromFile "question_file.txt"

另请注意,函数参数周围的括号在 SML 中不是必需的。事实上,如果您认为它们是,您可能很快就会犯语法错误。尽量避免冗余语法以提高清晰度。