#spaced-repetition #learning #education #scripting-language #command-line-interface #cli

bin+lib forne

一个图灵完备但极其简单的间隔重复 CLI,帮助你学习

6 个版本

0.1.5 2023 年 5 月 28 日
0.1.4 2023 年 5 月 26 日

#2108命令行实用工具

Download history 3/week @ 2024-03-10 39/week @ 2024-03-31

78 每月下载量

MIT 许可证

86KB
893

Forne —— 学习内容

Forne 是一个 图灵完备的间隔重复引擎,可以帮助你按自己的方式学习。这是什么意思呢?有几个部分

  • 图灵完备:Forne 可以使用 Rhai(一种现代脚本语言)完全编程
  • 间隔重复 是通过定期复习内容,在一段时间内学习内容的过程
  • 引擎:Forne 是一个库,任何人都可以将其用于自己的应用程序中,以添加间隔重复功能

但是,Forne 也是一个 命令行界面 (CLI),这意味着即使你从未编写过代码,也可以立即开始使用它!

为什么会有这个存在?

现在有很多间隔重复应用程序:Anki、Quizlet、SuperMemo 以及数以百万计的其他应用程序。但它们都做几件事情:将你锁定在一个算法中,使从你的笔记中导入变得困难,并且不允许你临时抱佛脚。

让我们现实一点:如果我们纯粹是为了自己的兴趣学习东西,那么间隔重复可能对我们非常有效,但如果期末考试即将到来,我们可能无法完全完成所有事情,因为生活就是这样。如果你正在使用 Anki 并且考试即将到来,祝你好运,因为临时抱佛脚和快速复习所有内容是非常痛苦的。使用 Quizlet 这样的应用程序则是相反:除非你愿意为付费版本付费,否则你将不得不使用一个只在童话中算得上间隔重复的算法。

关键是我们需要一个系统,它能够做这两件事:既可以让你长期学习,也可以帮助你临时抱佛脚,复习所有一组术语,并跟踪你发现困难的那些。此外,它应该能够根据你的喜好同步到你的设备,而无需你需要某个第三方账户,也无需将你锁定在一个可能会最终破产的服务中。

Forne 通过两种方式完全可脚本化来设计解决这些问题:

  1. 您可以使用简单的脚本语言编写自定义程序,将笔记导入Forne进行审阅,并且
  2. 您还可以编写和调整自定义的学习算法。

默认情况下,Forne附带了一个小型的(但不断增长的)间隔重复和速背算法库,可用于任何导入到程序中的集合(尽管一旦创建了一个集合,它将锁定到所选方法,如果您想使用不同的方法,则需要创建另一个版本)。这些学习方法可以存储每个集合中每个术语的任意数据,并且可以执行任意(但安全沙箱化的)代码,这意味着您可以从简单的“展示两次,她会弄明白”算法到科学支持的智能算法实现一切。

安装

注意:Forne是开发人员可以使用来为他们的应用程序添加间隔重复的库,也是用户可以使用来学习内容的命令行界面。本节是关于命令行界面,库的文档在这里

您可以从发布页面安装Forne,或者使用以下命令:cargo install forne,非常简单!

用法

创建一个新的集合

forne new <source-file> <output-file>.json -a <path-to-my-adapter> -m <method>

创建一个新的Forne集合相当简单,但需要了解两个关键概念:方法适配器。前者是指您用于学习集合的学习算法,这些算法是完全可自定义和可调整的。Forne附带了一些内置的方法(见此目录以获取列表),您可以在-m后指定任何方法,或者您可以为自定义Rhai脚本提供路径,该脚本将用作替代方案。有关创建自定义方法的更多信息,请参阅下文。

您还需要指定自定义适配器脚本的路径,该脚本在-后,这是创建集合的Rhai脚本。Forne默认不提供这些脚本,因为每个人的文件格式都各不相同,但您可以在这里查看一些常见的示例,或从中获得灵感。有关创建自定义适配器的更多信息,请参阅下文。

列出集合中的卡片

forne list <set-file>.json

您可以使用上述命令轻松列出Forne集合中的所有卡片,提供由forne new(如上所述)生成的JSON文件。然而,Forne有两个特殊属性可以在卡片上列出:它们可以标记为困难星号,具有不同的含义。困难卡片会自动由您选择的学习方法标记,而卡片如果测试失败则会被标记为星号。要仅列出困难卡片,请将- - difficult添加到上述命令的末尾,或者如果只想查看星号卡片,则添加- - starred。输出将在问题前加上Q: ,并在答案前加上A: ,用---分隔卡片。

学习一个集合

forne learn <set-file>.json -m <method>

上述命令可以用来在给定的文件集(如上所述使用forne new创建)上启动一个新的学习会话。你需要提供方法,该方法将被检查是否与创建集时使用的相匹配(如果不匹配,将返回错误以防止数据丢失)。此命令的输出将是一个问题,根据学习方法分配的权重随机选择,按下回车后,你可以说明你的表现(对此问题的回答由学习方法决定),方法将相应调整权重。默认情况下,Forne会一直展示卡片,直到你按下Ctrl+D,或者直到所有卡片的权重为0,这表示你已经学会了这个集合。或者,你可以在上述命令的末尾添加-c <max-count>以在查看一定数量的卡片后停止,这对于日常复习等情况很有用。

如果你想只针对困难或标记的卡片,你可以在上述命令的末尾添加-t <difficult|starred>

默认情况下,Forne会在你每次查看卡片时保存学习会话的进度,但如果你想从头开始,你可以在上述命令的末尾添加--reset。请注意,这是不可逆的,并且你之前的进度将永远丢失!

对集合进行自我测试

forne test <set-file>.json

一旦你学会了一个集合,你可能想确保你了解一切,这就是测试的用武之地:它们将只展示每张卡片一次,任何答错的卡片都会被标记,以便你可以稍后专门复习。与其他作用于集合的命令一样,你可以在上述命令后添加-t <difficult|starred>以仅针对特定类型的卡片,或者添加--reset以取消之前测试中可能取得的任何进度,因为默认情况下Forne会保存你做的所有事情,以便你可以稍后回来继续。

与学习系统一样,你可以在该命令的末尾添加-c <max-count>以限制你被要求查看的卡片数量。

请注意,你不需要提供测试的方法,因为Forne的测试逻辑是内部且非常简单的:你会展示每张卡片一次,答错的卡片会被记录为标记(你可以使用--no-star禁用此功能)。

测试系统的一个复杂之处在于,如果你答对了一张卡片,而且之前它是被标记的,那么它会被立即取消标记,这可能导致你失去了之前标记的卡片。如果你在进行最终复习之前进行测试,这可能会成为一个问题!如果你想禁用此行为,可以在上述命令中添加--no-unstar。如果你不想在测试中让Forne标记或取消标记任何卡片,可以添加--static

适配器

使用Forne的第一个挑战是将您的集合导入其中。Forne接受问题/答案对列表,但这并不意味着它不能用于更特殊的使用场景,比如三语种集合。因为Forne允许您编写自己的导入逻辑,所以您可以非常容易地将一个三元词转换为六个单独的卡片(每个卡片以两种方式指向另一个卡片)。这也使得像cloze词这样的功能可以轻松支持,并且是以适合您的方式。Forne提供了一个非常简单的机制来显示术语并帮助您学习它们:您可以完全控制它们是如何创建的。

适配器是用Rhai编写的,这是一种简单的类似Rust的脚本语言,编写起来相当简单!如果您之前从未进行过任何编程,您可能需要寻求ChatGPT的帮助,并使用我们的常见适配器示例,否则就尽情发挥吧!所有适配器都编写为简单的脚本,其中将有一个常量字符串SOURCE,即给定源文件的内容,可用,并且它们预期返回一个问题/答案对数组(例如[["foo", "bar"], ["q", "a"]])。大多数情况下,您可以使用正则表达式来完成此操作,而Forne为您提供了几个用于处理正则表达式的实用工具。

  • is_match(regexp,text) -> bool
  • matches(regexp,text) ->Array
  • captures(regexp, text) -> Array(这是一个数组数组的数组,其中每个子数组是正则表达式找到的一系列捕获;每个子数组的索引0是匹配的完整文本)
  • replace_one(regexp,replacement,text) ->string
  • replace_all(regexp,replacement,text) ->string

还有一个辅助函数用于简单情况,允许您插入一个带有问题答案捕获组的正则表达式,您提供索引,它们将被返回。如果您不需要进行任何进一步的处理,您的整个适配器脚本可能如下所示

return regexp_to_pairs(`my-regexp-here`, 1, 2, SOURCE);

在这里,1, 2表示第一个捕获组包含问题,第二个包含答案。0将表示整个匹配。请注意,我们用反引号将正则表达式括起来,以避免任何转义字符。

我们建议使用https://regex101.com测试您的正则表达式,并且非技术(和技术的!)用户都应该知道ChatGPT在生成正则表达式方面非常出色,甚至可以从您的笔记中创建问题!

有关Rhai语言的更多文档,您可以参考Rhai书籍,特别是关于字符串操作的部分。如果您需要编写自己的适配器的任何帮助,请不要犹豫,打开一个新讨论并提问,我们将很乐意为您提供帮助!

方法

学习方法在很多方面类似于适配器,但是Forne有多个内置的,并且您可以通过名称来使用它们(例如 -m speed-)。然而,如果您想编写自己的,以定制学习过程以更适合您,这很容易做到。首先,您可能更愿意调整现有方法而不是编写自己的,您可以在这里找到所有内置方法的源代码。

方法脚本比适配器脚本稍微复杂一些,因为它们需要一些关键元素以便Forne能够理解它们

  1. 开始处有一个const RESPONSES数组。这个数组应该包含用户可以对卡片做出的所有允许的响应。例如,speed-v1方法使用const RESPONSES = ["y", "n"];,这意味着当用户被告知卡片的正确答案时,他们可以说yn。您自己的方法可以定义任意多的响应,用户将被告知选择哪一个。
  2. 一个函数get_weight(data, difficult) -> f64。这个函数接受自定义方法数据(可以是您想要的任何东西)和卡片是否标记为困难,并要求您返回一个权重,它应该是一个浮点数(即小数)。然后,任何一张卡片被选中的概率是这个权重除以所有卡片权重的总和。
  3. 一个函数adjust_card(response, data, difficult) -> [..., bool],它接受用户对卡片的响应(保证是您在const RESPONSES中定义的其中之一),卡片的 数据,以及它是否标记为困难。它应该返回新的数据(这是您更新用于确定卡片权重的属性的地方)以及卡片是否应标记为困难。请注意,“困难”的含义完全取决于方法,它只是Forne让用户了解他们如何处理他们的集合的多种方式之一。
  4. 一个函数get_default_metadata() -> ...,它应该返回您想要用于卡片的data的默认值。

如果您的方 法取决于何时复习卡片,您可以使用get_seconds_since_epoch获取时间表示,它返回自Unix纪元(1970年1月1日)以来的秒数,如果您进行了一些时间旅行,则将是负数。

作为一个帮助您更好地理解所有这些的例子,这里有一个非常简单的学习方法

const RESPONSES = ["y", "n"];

fn get_weight(data, difficult) {
   return data.weight;
}
fn adjust_card(res, data, difficult) {
   if res == "y" {
       data.weight -= 0.5;
   } else {
       data.weight += 0.5;
   }

   return [data, false];
}
fn get_default_metadata() {
   return #{ weight: 1.0 };
}

该方法为每张卡片存储一个具有一个属性的对象,即 weight,默认值为 1.0,每次用户答错时增加 0.5,答对时减少 0.5。此方法永远不会将卡片标记为困难。在使用Rhai时,最大的“陷阱”通常是在输出对象前需要有一个井号(#)!

与自定义适配器一样,编写自己的学习方法是具有挑战性的,您完全可以打开 一个讨论 并向我们提出您可能有的任何问题,我们将很乐意帮助您!

最后一点:将本节readme内容粘贴到ChatGPT中并要求其为您编写学习方法通常会产生可行结果,尽管它并不完全理解Forne,所以您可能需要进行一些小的调整。如果您有任何问题,请随时在讨论中提问!

贡献自定义方法

Forne的使命是使学习内容成为学习过程中的简单部分,这需要尽可能支持更多的内置学习方法。最终,人们应该能够轻松地从互联网上获取自定义适配器,并且除非他们想对其进行调整,否则永远不需要接触学习方法,因为Forne中应该有一个丰富的替代库。为此,如果您以有用的方式调整了内置学习算法,或者您从头开始编写了新的算法,请通过 pull request 提交它,以便将其包含在Forne中!只要它可行,并且与现有内置方法足够不同,我们很可能会接受它!

此外,如果您正在研究学习科学,我们非常愿意听取您的意见,并且我们愿意通过Forne在实用层面上帮助实现您的研究!请随时通过维护者 arctic-hen7(您需要登录GitHub才能查看电子邮件地址)与我们进一步讨论!

许可和免责声明

请参阅 LICENSE

依赖项

~8–21MB
~240K SLoC