目录
前言
注:本部分仅分享一些我个人探索在 Emacs 中以间隔重复的方式进行知识复习的工作流的历程, 不知不觉就写得比较多了,其中涉及了不少设计与实现上的细节,算是我自己对这段经历的一个记录, 不感兴趣的道友可以选择跳过。
前言
最近有定期复习知识的需求,然后我尝试在 Emacs/Org-mode 中寻求解决方案, 那么就先分享一下我尝试的一些方案、它们各自的优缺点,以及我个人没有继续使用的原因:- anki-editor
Anki 是个强大且生态完善的间隔重复软件,而anki-editor
可以将 Org-mode 中的 Heading 通过 Anki Connect 导出至 Anki 中进行复习。 优点是能够在保持大部分格式的前提下,在跨平台且有云同步功能的 Anki 中随时随地复习 Org-mode 中记录的内容, 但我认为这种方案的问题是:- 两边(Org-mode 和 Anki)的生态有较大的割裂的,先不谈两边相同功能的插件孰强孰弱, 通过将内容导出到 Anki 的方式不一定能够很好地利用 Anki 那边的插件生态。
- 如果要为这套方案扩展一些功能,工作量较大且有割裂感,因为需要在 Anki 端实现具体的功能,然后在 Emacs 端去做适配。
- 如果每次仅进行简单的文本形式的复习却需要离开 Emacs ,对我个人而言有点不太能接受, 再加上在 Android 端已经有原生的 Emacs 可用, Emacs 的跨平台性和便携性对于我这个 Android 用户而言已经不再是问题, 所以我跳过了继续深入这种方案。
- org-fc
这个包的全称是 Org FlashCards ,应该算是在 Org-mode 中功能比较齐全而且比较成熟的方案了,性能不错,也有可视化的 Dashboard , 我自己不仅尝试使用过一段时间,也尝试过扩展这个包的功能,最终还是放弃了在其之上投入,具体原因如下:- 现有的功能与算法
org-fc
的功能表面上看其实不算少,例如默认的复习形式有翻转卡、填空、单词拼写等,填空有好几种隐藏方式, 而这些在 Anki 中,有的是需要加插件实现的,但在 Anki 中非常基本且重要的功能,例如限制每天学习/复习卡片、复习日开始的时间等, 这些在org-fc
中是缺失的,并且 Anki 已经支持了先进的 FSRS 算法,比传统的 SM2 算法有更好的复习效率与效果, 还可以针对个人学习习惯与所学知识进行自动的参数优化。 - 项目的维护状态
项目有很长一段时间没有什么主要更新了,我提交的 PR 也杳无音讯,最近一次作者最大的动静应当是作者对于集成 FSRS 算法的说明, 不过相关的在develop
分支上的提交也只停留在 1 年前。 - 代码结构和扩展性
前两个问题我认为都不算太严重,而这个问题是阻止我继续扩展这个包的最大障碍,所以这里展开说说。 项目整体看一下模块化做得还是不错的,但个人感觉很多地方设计与抽象在现在看来可能算不上有多优雅。 比如org-fc
将复习卡片及其对应的复习记录(即在什么时间对什么复习内容做了什么样的评价)是分开存储的, 复习记录默认以.tsv
格式的文件保存在user-emacs-directory
中,而复习卡片自身仅保存间隔重复算法输出的最新状态, 确实这样能够像作者说的那样避免污染复习卡片,但是要知道从复习记录到卡片状态的转换是单向的,或者说是有损的, 只要有全量的复习历史,理论上可以随意地切换使用的间隔重复算法或者适配算法的不兼容更新,仅保存某种算法的状态是不可能同时做到这些的, 所以将复习记录与复习卡片分离的设计并不是一个好的设计。再比如,如果需要在org-fc
中新增一个间隔重复算法,要实现 6 个方法( 即定义 6 个cl-defmethod
), 要知道算法从本质上就只应该负责数据的输入与输出,但在org-fc
里,算法模块和复习历史、统计是耦合的, 这意味着每多实现一种间隔重复算法(虽然目前常用的应该就 SM2 和 FSRS 两种),就需要造一些重复的轮子, 而且一个项目中代码风格变化的有点快,例如为了实现多态,在算法这边用的是 EIEIO (CLOS) 那套, 在复习方式这边突然又变成往一个 Alist 中注册处理函数了,看得有点一头雾水, 于是我在开发完成第一个插件 org-fc-embed (能够将org-fc
闪卡嵌入至正常的笔记中)后就停止继续在org-fc
上投资了。
- 现有的功能与算法
在探索的现有方案中没有找到符合自己需求的之后,就决定自己从零开始基于 Org-mode 开发一套间隔重复系统了, 框架层面不参考任何现有的代码。
特性
- 零外部依赖 :框架与算法本身完全使用 Emacs Lisp 实现,因此对于一般的使用情况无需外部程序,方便在 Android 原生的 Emacs 上使用,也方便用户自己进行 Hacking 。
- 功能丰富 :框架支持限制每日新学习与复习的数量、设置每日复习开始的时间,分步(重新)学习等功能。
- 高度灵活 :对于一份复习资料,可以共存多种不同形式的复习项目(类比 Anki 中笔记与卡片的关系),默认提供闪卡(翻转卡)与填空两种主流的复习形式。
- 模块化 :框架核心及其数据结构与算法/复习形式的实现分离,方便集成不同的算法与实现不同的复习形式。
- 细粒度的配置 :可以对每个全局、目录、文件,乃至每份复习资料、每个复习项目分别进行配置,来针对不同的复习场景与知识设置不同选项。
- 数据可维护 :复习记录与算法数据使用 Org 的表格 (Spreadsheet) 来保存,跟随复习资料进行同步,并且在复习过程中如果选错了评分,可以方便地进行撤销。
- 方便扩展 :使用 EIEIO (CLOS) 以及钩子作为主要的扩展方式,扩展一个新的复习形式或间隔重复算法,只需要实现对应的一个方法即可。
- 复习资料可嵌入 :如果是复习自己记录的内容,难免会遇到修改内容后需要更新复习资料的情况,尤其是在更新带有填空类型的复习资料时, 额外的维护成本是比较高的,因此框架支持了在不污染笔记本身的任何导出内容的前提下,提供了直接在笔记内追踪、同步外部复习资料的功能。
- 批量操作 :支持批量地对表格等 Org 元素进行挖空与导出,提高复习资料的制作效率。
- 现代化 :实现并默认集成最新的 FSRS 算法,以获得更高的复习效率与更好的复习效果。
演示
这里是一些简单的演示,详细的使用与配置说明请阅读 README 文档以及命令/自定义变量自带的说明。
闪卡
填空
项目
以上提到的功能特性基本均已实现,不过项目也仍在完善中,目前的开发重心可能会更偏向我个人的需求与习惯,大家有需求也欢迎贡献代码。 复习记录、算法参数等数据格式已经稳定,欢迎大家试用并反馈。
项目地址:https://github.com/bohonghuang/org-srs
- 另附 FSRS 算法的 Common/Emacs Lisp 实现:https://github.com/bohonghuang/lisp-fsrs