“间隔复习”, 会是自然语言学习与编程语言学习之间的联系吗?
我一直有个困惑. 自然语言的学习编程语言的学习, 究竟有无某种联系?
我可以随意地在不同编程语言之间切换. 固然, 不同编程语言的熟悉程度不一样, 但是切换到另一个编程语言时, 几乎不会有任何心理压力, 而且也相信我必然能做好.在某些情况下, 我甚至会刻意违背某些编程语言所谓的 “规范”, 来尽量写一些能在不同语言之间都相对通用的代码.接触一门新的编程语言, 大致就是: 配置好编译开发环境. 刷下官方文档. 熟悉下常用的 UI 框架, 状态管理框架等. 根本上, 是因为编程语言, 其实有某些超越语言的通行. 比如: UI 布局框架. 本质上, 我接触到的其实只有 声明式和非声明式两种. 具体到不同语言,不同框架, 无非是 API 设计的是否优雅, 用起来是否顺手. 另外就是, “设计模式” 相对成熟. 不同场景下的问题, 只要合理套用对应的设计模式, 一般都能解决. 设计模式本身,不是框架;但是不同设计模式,大都能快速地在不同语言中自己编码实现. 再然后,就是性能优化部分. 这就需要对各种算法等,相对熟悉. 这是我的不足,但是借助于Google, 满足日常使用场景下的性能优化, 也是足够了. 再然后就是复杂bug 的定位.不同语言提供的调试工具,本质上大同小异.简单的,就加点日志, 必要时断点调试. 甚至有时还需要二分法,快速定位到问题的大概范围. 而通常难以定位的,往往都是些多线程相关的问题.因为无法稳定复现,所以定位成本略高, 甚至需要一定的运气成分.
而涉及到自然语言学习, 真的有些让人迷茫. 在我成功掌握一门第二语言前, 我不敢妄言自然学习有何特点,有何相对优化的学习路径. 但是最近几天, “间隔复习”给了新的不同的体验.而这,或许就是 两大类语言学习之间的某种联系.
因为种种原因, 我大约累计了 240张卡片,没有及时复习. 说实话, 有些多.某种程度上, 超越了我心理的承受程度.当你做一件不是很确定效果的事时, 你能承受的挫败感或者心理压力, 是相对有限的. 你会忍不住想: 真的有效吗? 真的值得花费这么多时间吗?
好在,前几天接触了 algs4–1–3–49. 其中延申出的避免出现 精神压力波峰 的策略,让我受益匪浅. 在当时接下来的几天里, 我利用睡眠前后, 游戏间隙, 看电视剧等各种零散时间, 完成了累计卡片的复习.
在复习过程中, 发生了一些很奇妙的变化. 我发现首先是记忆的更准确, 进而对应场景下, 更敢说了. 比如 “要ります”. 想要就是 “要ります”,不想要就是 “要りません”. 但是因为太久没复习, 我不太敢用,因为我不确定自己的记忆是否准确,怕出差错. 好巧不巧, 在我复习后, 前几天, 便利店服务员结账时刚好问了我一句 “袋要りますか?”. 我很平淡地回复了一句 “要ります”。是的, 我现在已经不在意自己的口音了. 我会尽量模仿学习音频中的口音, 但是看了这么多电视剧之后,我发现, 不同人在不同场景下, 同一个句子的 发音,是可以适当变化的. 所以, 我没有必要模仿所谓正确的口音. 我的大脑能接收到什么样的差异, 我就做到什么样就可以了. 就像说中文普通话一样, 在北京时, 也很难有同事能根据我的口音推断我的老家, 因为我就像有不同的语言分身一样. 我如果想说方言, 甚至不得不在大脑中先预演下, 然后切换到方言模式. 逻辑有些混乱, 我想表达的是: 在能够听懂对方的前提下, 给予适当回应即可. 口音本身,没有自己想的那么严重.或者说: 你无法纠正你无法察觉到的口音差异; 而如果你能察觉到, 往往能很快纠正; 但是另一方面, 我们也只是把口音变成了另一个我们自己大脑认为的 “正确的口音”,仅此而已.就像: 播音腔固然标准, 但是估计不会有人喜欢和一个播音腔的人聊天吧.在可以接受的范围内, 某些因为背景文化特有的 “口音”,或许反倒会使一个人说话,更有某种灵性. — — 我们为什么要急着否定过去的自己呢?
回到问题本身. 我发现这种变化, 是我始料未及的. 在复习时, 我的大脑,甚至开始主动将当前复习的内容与其他某些内容进行联想. 比如复习了 “よくありません”,此时不然觉联想到经常听到的 “良かった”.两者其实是同一个词.前者的 “よく”,其实就是“良く”。否定中,常用的是跟着 “く”。如此, 两个在以前在我脑中毫无联系的独立词组,现在就建立了联系. 其中的关键是: 我没有专门去研究他们. 只是刚好是因为自己复习了下 “よくありません”.
关于学习本身, 我有许多困惑, 也有许多不同的想法. 我其中的一个判断是: 在接触 “新东西”时, 人的大脑, 单次能捕捉的 “特征”是有限的. 使用的不同学习方法,或者借助不同的学习手段,会略微提高大脑单次捕捉到的特征的数量, 但是总归是有某个特定的阈值的. 换言之, 学习的更好手段, 可能仅仅是 “更多次的接触”. 数量或者频率本身, 要比手段, 可能更重要.
所以, 我忍不住要想: 我所谓的编程语言的学习手段, 会不会刚好是暗合了 “间隔复习” 的原理. 刷文档,类似于单次复习. 边刷文档边跟着敲示例, 是为了提高单次学习的效果. 接触不同的语言相关的函数库, 是为了对语言的某一特性有更多的熟悉. 具体实践时,更多的使用,会加深对知识的理解, 或许更多的是因为使用本身,就是一次复习. 当然, 也不完全对. 我在阅读不同的技术书籍时就发现, 一个设计巧妙的例子, 往往可以大大提升对某个编程技巧的认识.
我还没有办法完全将 自然语言的学习和编程语言的学习进行类比. 但是显而易见, 间隔复习本身, 确实对自然语言的学习,有了奇怪的,超过预期的促进作用. 我现在甚至有点怀疑: 我无法将 编程语言学习和自然语言学习 进行类似的原因, 可能仅仅是因为 自然语言的抽象程度更低, 或许不需要太复杂的学习技巧,或者太多太深刻的 “理解”.
无论怎样, 鉴于 “间隔复习” 这次的奇妙体验, 我准备对 “间隔学习”法, 进一步加注.投入更多的资源. 我初始日语学习时, 还没开始用间隔复习.我准备将那些知识也立即纳入间隔复习计划, 并且优先进行间隔复习. 简单说: 会暂时暂停几天新课程的学习, 未来几天优先进行更早期已学习课程的间隔复习.
没有太多花哨的技巧. 我直接写了一个工具方法, 批量把更早期的未学习的卡片, 设为Stage 2. 这样就可以理解开始复习. 记忆深刻的话,进入 stage 3; 记忆不深刻的话, 进入 stage 1. 为什么是 stage 2 呢? 直觉吧. 没有严格论证. 因为我现在的卡片复习策略是可以在 stage 之间前后转换的, 所以也不用太担心初始状态设置的过大或过小. 真的难的话,即使到了 stage3, 后续可能也会在不同的stage之间,往复几次.
代码, 朴实无华,找个合适的位置,调用下就行了:
/*
批量修改卡片阶段的工具方法.按需使用即可.
使用示例:
# 可以放到 switchDeckAction reducers 里. 不要放到 Selector 里, 因为 Selector中, stage 只读.
let cardsState = state;
let deckIds = [ ... ];
batchUpdateCardStage(cardsState, deckIds, 2, 1703948400000);
localCacheCardState(cardsState);
*/
function batchUpdateCardStage(cardsState, deckIds, targetStage, targetLastStudy) {
deckIds.forEach(selectedDeckId => {
let cardIds = cardsState.deck[selectedDeckId].cards;
Object.values(cardsState.card).forEach(card => {
if (!cardIds.includes(card.cardId)) {
return
}
card.stage = targetStage;
card.lastStudy = targetLastStudy;
});
let subDecs = pimsleurState.deck[selectedDeckId].decks;
batchUpdateCardStage(cardsState, subDecs, targetStage, targetLastStudy);
});
}
调用一次后, 代码还要屏蔽下. 不得不再次称赞下 docker + mount 文件夹的方式来部署代码, 真的是太方便了. 写完立即就生效. 如果服务器重启, 也能基于 docker 本身的机制,把对应的服务给唤醒.
如此. 我就有 746个卡片需要复习. 按照过往时间估算, 平均每小时50个卡片, 大约需要 15 个小时. 显而易见, 这是远超我的心理承受上限的.所以继续化整为零, 把复习压力分散到各种日常生活中. 初步规划是: 剩下的两个工作日合计复习越 250 条卡片; 未来周六周日争取能把待复习卡片数量进一步降低到 200 以内.或许我应该立个大志向: 本周末必须把所有卡片复习完.. 不太敢… 显而易见, 我能承受的心理压力, 是有某个无法量化的上限的. 一旦过大, 另一个我,可能就直接开始罢工了… 没得办法.
呀呀呀! 祝我好运吧. 日语学习, 因为没有成功经验, 也不敢乱在不同的学习方法上乱下注… 如果间隔复习有用….那我就要起飞了…. 或许真的能破解 第二语言学习的奥秘……….或许 ….真的… 可以….