duangsuse::Echo
412 subscribers
3.85K photos
105 videos
574 files
5.15K links
duangsuse技术相干订阅
这是 @duangsuse 与技术有关的发布频道
duangsuse 的另外有 throws 闲杂频道
@dsuset
转载频道 @dsusep
duangsuse 有coding,github,gitlab帐号和bilibili帐号

极小可能会有批评zf的消息 如有不适可以退出

suse的小站:https://piped.stream
ps 另有别名 popf.rip
ʕ•̀ω•́ʔ✧ 🐶🍎🏠生死🐜
(>ω<)岂因祸福避趋之 一鿕
Download Telegram
duangsuse::Echo
C++ 里小心用 auto op=[](string s) {s.append(wtf);} 这样的东西,尽量全用 reference GDB 里除了基础 b,run,continue,show,list , stepi 是步进指令 next 才是单步, where/frame 切换上下文 finish 返回 p -elements unlimit -- expr 可以显示数据
#日常精神分裂 #cplusplus #plt
A: 宏或者模板有没有办法把 identifier 变成 const char* 啊,不想写多余东西真是的
A: template 递归实现的 vararg 好草啊,很多人都喜欢用
B: 感觉 C++ 模板像预处理宏系统的扩充一样,这样就有两个“模板”系统了……
A: 话说 C++ 为什么不使用惯常的子类型检查方法实现类型参数?非要自动填模板
B: 大概是 C++ 和 Go 一样是单态不支持子类型所以只能用模板?而且模板应该会暴露 sizeof 这样的元数据,对闭源库可能是必须的,能做元编程编译期计算也是好扩充
A: C++ 的 class 和数值都有兼容或自动转换吧…… 模板大概就是把型参让编译器一填,然后自己再去检查合规性,省得 in out 约束的,直接最大兼容化了
B: 也是,毕竟 Java,TS 这些类型参数基本都是编译期的,运行时全是 Object
这么看 C# 的真泛型也有点像 C++ 的模板, IL 层面存储类型信息
A: 说说 abeat 项目, glClearColor(rgba) 的参数化你打算怎么实现?
B: 只能是删了改到 shader 代码里,反正花了好大力气弄的动态加载。本来这个频谱图理想状态就是 C++ 只负责绑定频谱数组,全部绘制 OGL 执行的
A: 那么函数图相对上一版的改进应该怎么办
B: 支持选择光标模式为可以看到光标点轴和 raw vp,scale 的模式, xy range 的放设置面板里,必须的。上一版显示 raw 的信息(xrange 还是错的)以及把设置和公式列表放在一起根本是错的,你怎么还不明白
duangsuse::Echo
我 DIO 败了😂,明明没好气的说自己用的是鬼画符,看来还是比不上各类前端大佬鬼画符。 要是我,可能选择把自体判断和 父妻=$母 这种东西给移到另一个“绝对准确”的模块里,而且数据要压缩就会选择脚本预处理,字符串内存优化就会选择加一层恒等替换字典,总之绝不会另外搞一套 notation... 😒 另外动苏非常清楚这个东西绝对不可能有批处理的应用场景,权衡利耗后我觉得完全没有压缩数据包或内存的价值,性能也绝对不重要(不能再快就是了) 断舍离就是这么干脆😋 毕竟写的东西多了,也明白性能这个东西是不可臆测或不可企及的…
#日常精神分裂 #relation #functional
A: 那个亲戚关系计算器,你还说人家做的不好,这不,你不也没做成了么
B: 是鸽后面了啦,今天又有一些新想法,可以改进特性而且保持程序接口一致
B: 首先是关系的,如果认为「父父子」(大爷的儿子)也是「父父」的话(兄弟的孩子也是一家的孩子),「姑姑」这样的称呼就跨单个的亲子关系了
A: 这还真是难以理解
B: 这个不重要,关键是反向称呼的本质其实应该要自动处理才对: 「父父」是爷爷,而「子子」就是反向「!父父」,「孙子」才对;对「我子」来说,「我子子」就是「子」这样。(有点 relative path 的意思了
B: 我还发现 notation 可以有更多变换, 父^5 和 长=哥|姐 外,还可以引入「姊」「娣」自动加「长幼」的前缀(不过,这样就要预处理过程 flatMap 展开缩写了
A: 最后这个被否决了,理由是「亲孩长幼」四个字组成的也不过几十条,复杂化算法不值得?毕竟代码是给人看的。
B: 我觉得可以考虑一下在查询语句里支持 姐|妹的儿子 这种……
A: 那子程序的返回类型就有点麻烦了,用途也小,还是不要麻烦了(孤立支持一下父&母 这种并称算了),支持 父^n 这样的缩写就够了吧。
B: 反向关系很重要,规则是 (父父 爷爷 !孙子) ,如果我用 !父父 能查到反向称谓,为什么更合理的 子子 就查不到了呢?其实反向不应该做在 妻父子 (=岳父的儿子) !_=(爸爸的女婿) 这样的称谓里,而应该做在 妻父子 !_=(父女夫) = (爸爸的女婿) 这种
A: 那么具体怎么操作呢?这种自动从数据构造反向关系的方法?
B: 我觉得应该定义 (反向 妻父) = (女夫) 这样的关系字典?
A: 首先,这么做是对反向称呼的扩展,因为数据里只有 (妻父=岳父) 的对应关系,当然可以利用别名系统增加反向称呼 (岳父 !女婿) ,问题是你要知道「如果以岳父视角看,我和他是什么关系」,答案是 (反向 妻父) = (女夫)
B: 那我给你「女夫」,如何答我「女婿」
A: 把反向称呼的数据填一下, 孩(子女)/亲(父母) 为相反关系,查询 (反向 女夫) = (!妻父) 就成了。
B: 你可真是个小天才 :P 那就这么愉快的决定了。
A: 对了,那你之前说的那个人是怎么实现的
B: 噢,看了一下,那个是同时定义了 (d,h=女婿)(w,f=岳父) ,对他们来说 ! 这个运算符反而是特别做的(不像现在 的安排应该是直接查询)。
我们之所以这么麻烦翻来翻去的就是因为数据结构格式不同(同时有正反向称谓 就避免重复定义关系链条了),其实目前的模式也就是它的模式,没做「对方称呼我」而已
B: 总结的说,就是一个先支持反向关系再支持反向查询,一个先支持反向查询后才能实现反向关系。
A: 这么看你的在方法思想上也没有什么更高的地方啊😒
B: 是呢,不过我的数据集比较简单,单字符切分(js的之所以必须留逗号就是因为作者没法支持不定长的并列单项,不会写 tokenizer),后期也可以加预处理替换来压缩什么的 功能能做到一样 可以试试🌝
tail -n+2 |python -c 'import sys; s="".join(ln if i%2==0 else f"**{ln[:-1]}**\n" for i,ln in enumerate(sys.stdin));print(s)' #日常精神分裂
过两个星期就开学了,想整理下之前计划的项目。完了,我好像忘了项目队列上的一个项目。
是引用丢了还是整个丢了?它处在什么位置?
记得当时记忆用的是 大小小 大小小 的顺序,好像是 第二个大大丢了,在 fourier 之后 hachiko py, mohu cpp 重写之前。
项目是什么平台的? linux? windows? 有没有用到 DOM, Qt, OpenGL 等框架?
应该是跨平台的,肯定不是 Qt 或 GL。
项目和二进制格式、输入输出、网络、数据库、算法、绘制、编译原理、API 设计有没有关系?
应该都没有关系吧,是单个的应用,而且输入输出哪个程序没有啊,算法也不少吧。
项目有图形界面吗?还是通过 CLI 或 socket  流呢?
应该有界面吧。
是不是 CASCompiler 重写?那个已经有了也足够大 。
不是吧…… 这个是后来岔的。
是不是完成 LittleDict ?
可能吧,可是它也是小项目啊?
应该不算了。 fourier 和 mohu 都是单页的,LittleDict 已经可以说是大点的东西了。
刚才就记下来应该完成了,那就不用改了。
关于这些杂七杂八代码与结构的设计,你有什么建议给大家呢?
我觉得吧最关键是要懂拆分,要能看出程序所需要最关键的子程序和这些片段所依赖的变量(好像 make 的规则一样),然后还要把「领域」和「下层API」的变量 集区分开,比如 video 的 w,h 宽高和 fps 帧率 t 当前时间就是领域的变量,什么 encoder, decoder 就是应用框架的变量,不一样的变量集不同对待。
#日常精神分裂 #旧事重提 #Java #JS #PLT #cplusplus #project
A: 啊真的很头疼呢, JPlayer 的 fix 和 depth.html 附赠的 Myson 数据描述语言……
B: 像往常一样,我们一起想想吧。
A: 首先说 JPlayer ,这个原先是作为重写 Yuuta 大佬项目的东西,变的蛮多的,后来也有完全的 C++ 重写。
这个东西最后也是长期熬夜 timedout ,失败点是为优化性能加的 Ringbuffer 队列缓冲区利用有瑕疵,导致最后一次缓冲的内容没放完退出
B: 你还记得它的大体数据流程吗。
A: 当时怀疑 Java 计算速度慢所以用的缓冲器预计算一定内容,整体是 while(frame=next()) 呃不,是 while (escape=que[incPtr()]) if(samePtr()) genChunk() 。
B: 对了,你缓冲的帧是什么数据类型啊,二维数组吗?
A: 基于 frame pix diff 的 ANSI escape string ,这个当然是在 chunk 计算的
B: 生成新缓冲帧的程序你大概是没隔离吧,按当时的设计,应该是 genChunk 收到 VideoIO throw NPE 就跳出绘制loop 了,即便最后一块刚刚准备好。我建议 catch 住NPE ,如果 !samePtr(p,p1) 即还有余帧就继续播放,否则才真的退出。
(接下来一段被证明是误会)
A: 这大概是不利于性能的吧,最后一块的每帧都要 catch ,而且还要局部 landingpad ,函数级有一个了。
B: 你也说了是 jacoco 解码器 API 的问题? throw 是不可避免的,只能说或许可以把输出帧的做成子程序,最后一块的 catch 里直接消耗完队列,或者加个 bool ,未结末时先 if 一下避免重复。

A: 我总结一下流结末的情况: genChunk() 生成某帧时 catch 到一次,但是缓冲区没放完,继续放完这一块,再 catch (输入终末)了发现缓冲区没了,就停止播放。
A: 挺简单啊。那么 Myson 该怎么办,这个语言挺不常规的,既有缩进语义又只支持对象?
B: 首先我们先明确下,既有 heading tree 是怎么解析出的。
显然是每个DOM元素都有「深度」,然后非 h1~h6 的元素默认上一次深度或0 的 +1,所以说是「以能解析 Python 的算法解析标题嵌套深」对吧。
A: 可 Myson 就不是直接分开的,觉得要写 RegExp Lexer ,不敢写,挺麻烦的。
B: 看了语法设计,是不支持 array 什么的,只能 key-JSONValue 吗?
A: 是的,只支持一种嵌套,就是更深=子对象
B: 这么说没有行尾冒号也没问题喽?
A: 按理说是这样的……没问题吧?
B: 我能理解,反正你打算完全用缩进深度吧。你又没有支持 optional 多行的语法,唯一的不优雅在于有冒号没用,没冒号的话已有 value 的行后尾随缩进增,就不易看出冲突了。
A: 那具体如何实现呢。
B: 只需要 split lines+trim count 就可以了,之后 line 实际上就是 k-v ,遇到更深的就视为上一行的 v ,递归展开成 JSON.parse object 的形式,检查下不冲突就行了。当然,缩进莫名上升这种就检查不出来。
比如:
小明
名字 "明天白"
年龄 14
朋友 ["小张", "小红"]
小张
名字 "张大奇"
年龄 15
最爱
世界 "你好世界"
伍六七 "excited"
突然想到可以这样.. Object.assign
某人 {"id": 1}
姓名 "小白"
朋友 "小黑"


A: 听你这么一说我都有把这个 publish 到 npm 骗 star 的欲望了(
B: 我觉得这个挺浪费的,当然 JSON 也一样,key 重复了那么多次,不方便写也不方便传输
A: 有什么办法呢,下一层是 csv 基于 row 存储,那个是 efficient 但是只能存 object array ,而且也不能有嵌套对象
B: 我觉得你加上内联 CSV 的特性,就真的可以骗 star 了。 噢对你还应该把 JSON2Myson 写出来,就是带 indent: string 字段的 TreeWalker 是吧。相信你会写,这对工具化很有用,毕竟 JSON 不好看
A: (若有所思)
B: 你还可以把这个做一个 DOM Tree 的后端,甚至直接变成一个模板语言
html
head
meta {charset: "UTF-8"}
body
a {onclick: "alert()"}
_text "你好。世界"


B: 对了, JSON2Myson 用于带缩进输出的递归子程序还可以对 k-v 里的 v 立即处理而不必再下层递归,反正顶层又不支持单个值,就当是优化了。
A: 打住打住…… 这当然可以,其实就是翻译 {} 吧。区分 Attr 和 childs 对复用性有些挑战,但我相信能行。

A: 对了,我还有两个小点子:
(1)infsw 可以增加 timedline MM:ss ; 此外还有 exec 与 statics 子命令,以及 event name 的自定义和自动修正 failed watch 的 argv filter ,因为 watchdog py 的 watch medo/exec 和 inotify-tools 的 cli 都太麻烦,就自己写。
(2)之前的 OGL 频谱透明动画可以加一个纵反向的功能,利用 xdo 跟踪到窗口顶端什么的,像 supertuxkart 这样的游戏就可以当音游玩了(迫真)
A: 说起来卓依婷是谁啊,写的歌好熟悉呢
#日常精神分裂 #Haskell #functional #relation 推荐不要看的胡言乱语。
A: 听见人说 Rank N Types 可以弄出 p(p==not) (: forall x. p(x)==not(x)) 的关系式
B: 不过这个你自己也不明白吧,说白就是 p(q) = not q 时 q ,正确答案 q 只有一个,但是 q=(forall x. px==notx) = True 时 p=False , p!=not.not.not.not q ... 还有一大堆 not ,就是这里没法得到答案吧
A: 为什么有一大堆 not 呢
B: 为了保证 p=not 的定义, p(p==not) 应该里 p 的定义是不一致的,第一次是 not True 但导致 p=not.not=itself ,第二次又变成 not False 而 p=not,我们想做的是用比较形式化的方法从某一面「判断」这个东西是无解的,但它到底是等式,还是关系式,还是别的什么?
A: 那还是看看 rankn type 是什么吧。
B: 最简单的说法,对 id :: a -> a 里 a 有 Int, String 等可能,但是如果有 f :: a -> (a -> a) -> a ,f 里 a 就只能是任意一个类型,而在括号里加 forall a. 那 f g = 后面就能同时 (g 1) (g "") 了,但这只是 Rank 2 type 。 Rank 是「重评估」的意思, R0 t 是单态 R1 就是正常多态,如果要更多 Rank , (forall c . (forall a b . a -> b) -> c) -> d 就是一个 Rank 3 。 我之前还说不可能 forall a. forall a. (a -> a) 呢(没意义 a 已经在类似上下文 绑定过了)
A: 话说 type 和程序体有什么关系啊。
B: 一个常见的误会是系统化的类型和程序是相互依存的,比如完整的程序带来了类型信息,其实除了 type inference ,程序的组织结构和类型标记是两个独立部分,类型只是限制程序 它自成体系,甚至可以说能检查程序只是它的副作用。
A: 说起来 haskell 的 a b c 到底是怎么检查的啊
B: 类型就是符号之间的关系,符号绑定了语法树的模式和其它关约束条件。 hs 里这很简单,只有一个性质—— consistence 一致性,比如有 (+) :: Int -> Int -> Int ,那 1+"1", 1+0.0 就是无效的, 1.0+1.0 也是无效的。作用域单一没有同名重载,只能约束 (t,t) -> t ,如果各处的 t 是一致的就没问题,否则就错了。 typeclass 也是类似 trait ,其实类似一个小插件,是 (Show t) 拿到实型去查对应 instance ,查到就能选择多态 找到的实现版本而已。
A: 真的不明白 RankN 和有什么关系呢,毕竟 rank 是 polymorphism ,作为 type constraint 为什么会陷入死循环呢🤔,要不谈谈 rev rev=id 吧
B: 那个就是把 0 和 iLast-0 对应吧…… 和 xs.rev()==xs.rev() 不一样,是要 xs.rev().rev()==xs ,怎么解构呢,我区分不出 foldl 和 foldr 啊,函数式分不出调用顺序 理论上不存在栈这东西呢, foldl f v xs = foldr (flip f) v (reverse xs) 啊
A: 问句题外话,为什么不能 add :: Int Int Int 啊,而且遇到 f not p 时中间也得加 $ 或 <$> 的
B: 一个是并列一个是 infix 了,编程语言可没你聪明不知道 not 不是一参数 要加括号
B: 你到底有没有见过正经的 Recursive Type 啊
A: 递归类型是什么,为什么要递归?层数有限制吗?是不是有限性?在无限序列上有限计算 算不算用了递归类型? Py typehint 里 -> "self" 算不算?
B: 肯定不是啦…… self 是 py 作用域设计的问题,3.7 lazy 勉强解决了,和 recursive type 是无关的,这个大概和 Kotlin inference 一碰到就要 workaround 的递归返回值有关吧。
A: 当然基于 car cdr 的 apply transform 我都会,C++ template<T, ...Rest> 嘛
B: 那还真是好普通啊
B: 别灰心嘛,还是需要你们这种布道者的

A: 有时候感觉我们这些做同级翻译或者 LLVM 前端的人写的编译器本质是元编程的一种表现形式,有时候觉得完整的编译原理课又是照本宣科,除了后端都是重复,到底怎么样是好啊。
B: 我看到一个有意思的视频,一排柱子一根根升起,给你一个 i 你能不能做出动画来
A: 动画师估计挺麻烦吧。 普通人可能要求 timerup 后移 单个动画 ,但这个应该建模成 [0, 0], [1,0], [2,0], [2,1] 这样的「逐列递增表」,实际依然靠 i ,但是可以拿到过程中的所有状态。
B: 最方便的大概是直接一个乘除法吧…… 批量计算好
A: 感觉还是做到 assembler 前比较好
B: 你是说 SSA Value 和寄存器分配吧。 分配是独立的算法,但我可以告诉里不分配,完全溢出到栈上也是能实现的。只是要生命期内所有引用,局部 unified 就可以。 作为 stack ptr 参数还是 opcode reg input/out 的区别而已,如果用栈,也无所谓有几个 operand 或有几个AST前层,唯一又能统一的输入输出地址而已。
#日常精神分裂 #沙雕
A: 看完《转生史莱姆》旧集命名一段我突然冒出个问题,如何杀死一只史莱姆?史莱姆有核吗?
B: 史莱姆无限可分,无法杀死
A: 说到物质无限可分…… 我想到了毛泽东的“原子无限可分”了。 其实不论身份的话,这个论断也是一种合情理的猜想吧。
B: 反对的都蹲大牢去了,你觉得怎么样。
A: 毕竟对普通人来说自然界的什么东西有极限就显得很奇怪,就像爱因斯坦的「上帝不可能掷骰子」?那如果不从问题本身讨论,就问怎么「劝」一个持这种常识的人相信「原子不能再分」呢?
B: 我觉得可以这么比喻吧,「人体可以无限拆分,但是拆到一定程度就会分崩离析,失去原有性质,不能再叫人体的子部分」,再为了贴合毛泽东的理解套一下实例,再给他个台阶下(之前的理解部分正确 但有一个微小细节),应该就能被接受了。
A: 不讨论这个了,你觉得 GNOME 的「自然滚动」滚轮视图而非内容,怎么样,怎么实现 Android 等触摸手势上的「末滚动动画」?
B: 反向滚动我觉得就是个 trick,末滚动动画的话需要知道单次滚动的速度,必须有 onTouch Start/End 事件和一个 t0 ,必须能读写 pos 。
A: 触摸滑(滚)动就是一个动画,为什么要有 on start/end?
B: 你可以把它理解为 window 上 drag 的实现,必须有 point0 才能知道 pos 的单次偏移量,至少要记录按下状态,并不是说 onPointerMove 就够了
#日常精神分裂 #DOM #game #js
A: 你看到了吗,那个从视口顶部丢球球下来,像俄罗斯方块一样的球碰撞游戏,是叫合成大西瓜来着
B: 那是个逻辑相当简单的游戏,也看见有三四个人做了翻版(奥利给等),如果按环节重复、更新规则、动画细节三项而言,细节不超过六个
A: 如果我们利用 canvas 做碰撞检测复刻一个,你觉得怎么样?整个绘制只有 Ball(p,r) 一种类型两个参数!简直和只有 fillRect 的贪吃蛇一样简单
B: 和 web asteroids 的 doc.elementFromPoint 不一样-_-|| 这次要手写 2D 游戏引擎碰撞检测部分,除了基础的加速度和碰撞方向检测;老实说都是数理密集算法
A: (不考虑与边界矩形的碰撞)我想到了三种方法做纯圆球的碰撞检测,首先是遍历球表算距离……
B: 没用!这样相当于每个配对你都要检测一次,要知道这个游戏后期会有 20 来个的,为保证不穿模,每一帧都计算?!
A: 那我参考整体动量,间隔毫秒或者帧号判断呢?
B: 都说了会穿模了
A: 第二种方法,参考物体的运动方向延长线,看交点,每对 ab,ba 缓存下只算一次
这种方法也可以用来优化一个物体不动的碰撞,或可预判碰撞发生时间,有变再 cancel 重算
B: 好啊,你怎么取射线和圆的交集?
A: 第三种方法,其实理论上只有画特效需要用到 canvas ,其它的尽量用 DOM 元素,就可以利用浏览器的既有算法,我知道有个 Element.nearest(selector) ,这样每对物体检测一次 d(p1,p2)<(r1+r2) 就够了;对边框是特例,只要对所有物体增加 x,y in clientRect.innerDist(r) 就可以了
B: 是个可取的方法,你不会用框架吗,整个游戏只有 ellipse collision 和 gravity 、force ,再简单点就只有放球和贴图,碰撞只是换贴图+增长,球与上框碰撞结束而已。
A: 嫌大了。 DOM 已经足够强大,何须更多修饰? 高射炮打蚊子

B: 好了,谈谈复用问题吧,假设你不用框架,却又写了个用途单一的正圆碰撞检测算法…… 我猜测应用部分是这样的:

gameStart() = rateLimit(waitPutBall, 4000)
onEach(ball)
limitInRect(world.rect.innerMinus(ball.r), ball) // 模拟边框碰撞体
if ball.p.y<yTopline: gameOver()
waitPutBall()
ball = newBall(randPick(cfg.sizes), randPick(cfg.colors))
ball.y = yTopline; ball.g = cfg.weight
onmousemove = ev=> ball.x=ev.x
onmousedown = ()=> world.attach(ball) // 球开始下落
onCollide(a,b)
a.r += b.r
a.onChange()
b.remove()


gameOver() 的条件也可以换成在放球和最近球的碰撞检测 避免每个都判断

A: 我相信关于代码复用和框架组织,咱会有办法的!
#日常精神分裂 #parsing #JS #scheme
A: 之前说好了要写的 s-expr 解析器,看来是写不了了?还打算复用 JSON.parse 的,以及支持缩进布局,那样就会很有价值吧
B: 之前还打算支持 {;} 可选缩排的,发现和 data notation 侧冲突了,看来是眼高手低😂
A: 其实关键在于易实现性吧,你想用尽量少的代码和低层API实现给应用用的解释器,无论解析结果怎么用?
B: 对了,子序列法比流递归下降法代码量少吗?
A: 无论从什么角度看,加上对 JSON 子语言解析器的复用都不会更省啊……
S表达式是由 Atom/List 两种元素组成的嵌套表,或者说 值/调用参组 的树形列表,一般首项为函数值, 尾余为参数;是三十行以内能实现带调用和 (let 的 动态作用域版。

譬如在解析 () 里的 a b c 单项中,我们实际在读 SList 即 toplevel 的 Expr list ,假设 a 是另一个 () 则:
流递归下降从 ( 后再解析 SList ,它主动完结后刚好在 ) 闭处
无论是靠返回结束索引号的非规范递归下降还是 StringView substr 返回消耗/片段的皆此

子序列在 ( 处直接 findPairedIndex ,这个算法只需处理 "\"" 字符串然后取闭包含子串递归解析,不过这个扫码过程是没有缓存但只需计数开括号的,相对外部()会多数很多遍。

我可以觉得,不用流不等待「不知何处结束」的子串解析结果再检查闭括号较易理解,但是它实际做了无用功,调用栈还是那么高。

B: 就没有什么又易懂又简单的方法去递归下降吗?子序列真的有那么无用吗?
A: 我打算用 function 值把流建模成 s(0)==length, s(1)=="a", s(-1)(1)=="b" 这个样子,还算轻易。
JSON 静态变作流解析有方法,递进长度子串+检查异常pos取头 足矣,全长仍错时即无解析

递归下降如果不显式 substr 而是交 (共享/复制&同步) StrView 的话 #parser 的确对新手不好理解,但套路不复杂。

子序列的话我考虑了一下,如果我们采用复杂点的 visitor 去边解析边执行(自然也可存下再执行)是能实现 if 里兼容一侧语法错误的,显得很 Javascriptic 🌝

B: 很神奇,具体怎么做呢
A: 存参成树允许再遍历的 visitor 就不说,可以给部分递归 () 的 case 变成 ()=>readList(s.substr(findPairedIndex(s,))) 闭包,然后参数求值(反正这语赋值处只有实参组) 时支持惰性求值的程序里兼容下先解析。

其实我并不喜欢边解析边执行,只是有时候(比如 %s fmtstr 等)工作就是很死板所以无所谓了,况且这分块惰性解析涉及函数调用求值序的问题,那就是扯到函数抽象、词法作用域里的闭包 #ce #plt ,不简洁不能体现对灵活的嵌套处理过程的即时利用