duangsuse::Echo
718 subscribers
4.26K photos
130 videos
583 files
6.48K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
我开始觉得保存流位置这件事应该是由 items("abc") 这样的解析器,而不是 seq, or 什么的解析器完成了
finally,在我死肝debug两个小时后,一吃完饭我才最后成功弄 pass 了 tests
只是加了一个 AtomParser 的 mark/reset 调用而已,居然……

我一点都想不明白,为什么seq里的tryRead(也用了MarkReset)不行,单独MarkReset可以?是不是还有bug?
啊,我艹,果然是写错了!还好我牢记曾经在酷壳看到的『修问题要修在root cause』基本观念,没有轻易放过它
要不然指不定我下次还要再犯!

我最开始的设计也有容易混淆的地方,我把 pfail 和 Kotlin 的 nullability 操作符混在一起了,一些地方没注意到……

难怪我看见里面的逻辑执行了两次,感情是混用了 null elvis (?:) 算符……
Null 『传递』就导致 MarkReset as? 的结果和你后来 let, run 里面逻辑的 null 可能性混淆了,这是一个不常见的坑…… #Kotlin
这个让我调试了2h+的问题啊……
这么多代码,已经足以解析 JSON 的字符串了,当然写法不止一种(repeatUntil(buildCatStr, seq(takeTerminate(element('"','\\')), or(eoString, escapedPart)), item('"')))也行、有了reduceOr/leftrec左递归也可以。 ParserKt 不是一种 DSL,所以 Kotlin 能够描述什么它就能描述什么,不需要太多麻烦的东西,高阶抽象章口就莱。
在我运用自己的迫真数据依赖和过程式里技后,总算是拖了两个小时解决了递归解析的问题;可以用了。
Forwarded from dnaugsuz
动不动就是 null,Kotlin 的编译器检查不出来,它不知道有些东西(比如lazy、inline getter 的)的一些数据还没初始化

我改了很多次,基本都是:
+ map 要用到的 val element 没实际上拿到 val scalar 的值
+ scalar 是空的
+ init {} 陷入无尽递归……

hhhhh,后来我想了半天只得写了个 deferred Parser,因为构造的时候没法直接拿到循环的指针嘛…… 为了保证不空只能等实际用的时候才能断言需求已经架构好

有没有大佬知道,是不是怎么安排可以避免使用架构器外的 deferred(只是好奇)
终于完成了,欸
最后我写三个小程序,算是迫真完成:

1: JSON dump (prettify)
2: JSON2YAML
3: JSON path

然后这三个程序是这么安排命令行的(怎么莫名其妙用到了队列……:

a.json b.json c.json -dump
a.json -toyaml a.yaml
x.json -path $[0].name -path $[1]


[file...] -dump (-indent 2)
[file] -toyaml [new file]
[file] -path [path...]

然鹅,JSON Path 我还要再写解析器…… 不要哇,递归解析器很虐的(莫名感觉)
我以为利用 reset 就可以解决不应该的可变数据生存周期的问题,其实我错了,我真蠢,真是太脑残了。 现在这个样子递归解析也没有用是多可笑啊hhhh
弄一大堆 branch 性能本来就有待优化,还弄什么「finish」「Folding.Effect.reset」,还弄什么 Feeder MarkRest,真是多此一举;我都忘了自己要写 MarkReset 干什么
duangsuse::Echo
Photo
以上输入,反正就是只要有递归的情况,Box unwrap 全部会莫名其妙错误,我真是哔了狗了。
java.lang.ClassCastException: java.util.ArrayList cannot be cast to org.jison.Json

然后你调试看看,就会发现其实错误是在(目前因为没有特别处理 Parser 的格式化和完整面向对象建模,就是快速版本的而已,所以调试起来很麻烦)

kvPair.joinBy(tCOMMA)
.then { it.toMap() }.surroundBy(tLB, tRB) then { Json.Dict(it) }


//...
seq(partialList(1,4),
ws, string, ws, tCOLON, element) then { Pair((it[0] as Json.Str).literal, it[1] as Json) }
seq(snd, ws, deferred { scalar }, ws).unwrap()

在这里,element 的解析结果以 selecting(1) 折叠居然是一些 spaces(ArrayList)!所以 1 难道不是永远代表 deferred { scalar }?莫名其妙,真是莫名其妙。
只不过是因为某个 selecting 的实例被递归使用了而已,所以就被破坏了,明显是作用域没想好,这种烂代码还有什么可以说的呢?
https://t.me/ice_learn_agda_internals

不愧是冰封哥,一天(大概是他在地球对面)时间就发了 47 条消息广播
这个频道居然是要重置 Agda???
……不愧是冰封
duangsuse::Echo
以上输入,反正就是只要有递归的情况,Box unwrap 全部会莫名其妙错误,我真是哔了狗了。 java.lang.ClassCastException: java.util.ArrayList cannot be cast to org.jison.Json 然后你调试看看,就会发现其实错误是在(目前因为没有特别处理 Parser 的格式化和完整面向对象建模,就是快速版本的而已,所以调试起来很麻烦) kvPair.joinBy(tCOMMA) .then { it.toMap() }.surroundBy(tLB…
其实我应该用面向对象类,而不是 Function1<Feeder<T>, R> 这种方式来抽象 parser 的,现在一大堆 stack trace 不好看……

当然新的 ParserKt 有利用 Preety Print abstraction 的方式为每个 Parser 提供(无论调试抑或是实际报错都能用)的 Preety repr
我觉得 Parser 需要基于抽象类建模,而不是一个匿名的函数闭包……
这样的话,如果一些比较严谨化的东西也可以对 Parser 们用匿名 object 了(前提是大部分 parser 都要 open,至少是 seq 系),当然 deferred Parser 还是不可能省掉,要不然 initializer 无限递归或者拿到 null reference
其实也足够好了…… 死没办法

typealias Parser<R> = KParser<R?>
typealias PositiveParser<R> = KParser<R>
typealias PFailure = PositiveParser<Nothing>

inline val nParsed: Nothing? get() = null
inline val <PR: Any?> PR.isNotParsed: Boolean get() = this == nParsed
inline infix fun <PR: Any?, R1> PR.parsed(crossinline then: (PR) -> R1): R1 = this?.let(then) ?: this

唉…… Kotlin 不能 typealias PResult<R> = R? 这种(别怪我偏执)
要不然我可以写 ps(feeder) parsed { it.let(f) } otherwise { feeder.pfail(…) }
不过用 (?.let) (?:) 也还算好


老用 extension function 对 JVM 来说也不是多好看,既然 compose parser 很常用不如就直接加入继承结构里
我哭了,虽然代码很难看而且缩进用 Visitor 没用到精髓,总算是完成了。
我要写别的东西…… 好无聊
ParserKt 的 mustSeq 是判断使用处可不可能 or 加的,好傻逼。
真是太愚蠢了,但是简直没有办法,难不成 or 还得手动给 subparsers 加逻辑?
简直蠢死了,为什么要看使用处;这么说用 Haskell 的多态方式还方便一些

or 就不能要 seq 是 PositiveParser,别处都要呢?不要就用 mustSeq 或者 toMust?可是那样代码真不知有多繁复,明明本来就应该是 must 的为什么还要默认 may?这就是多态,可是哪里来的多态、我为什么要多态

我用 toOptional() 怎么样?可是那样的话到处都是 toOptional,都怪 or,真是垃圾子解析器,虽然它可以说是最有用的一个了……

虽然对面向对象编程 or 根本不应该出现,为什么要有or,br 直接 peek&branch 不好么?

看来只能让 seq 比较独特,or 自动把所有不optional的subparser包一层optional好了

可是默认所有都 must,到处抛异常性能严重问题

也不对,mustSeq的思路本来就不对,错了为什么要抛异常?难道不可以在 or 的最后一个分支加 parserFail?不是一样么?or都用上了凭什么要toMust()?
duangsuse::Echo
简直蠢死了,为什么要看使用处;这么说用 Haskell 的多态方式还方便一些 or 就不能要 seq 是 PositiveParser,别处都要呢?不要就用 mustSeq 或者 toMust?可是那样代码真不知有多繁复,明明本来就应该是 must 的为什么还要默认 may?这就是多态,可是哪里来的多态、我为什么要多态 我用 toOptional() 怎么样?可是那样的话到处都是 toOptional,都怪 or,真是垃圾子解析器,虽然它可以说是最有用的一个了…… 虽然对面向对象编程 or 根本不应该出现,为什么要有or,br…
错了统一不抛出异常、错误统一让 effect 子结构注册到流上下文里去(指使用 clamDown 镇静解析策略恢复默认值的情况)
其他错误直接让 parserFail 来提供报错信息
or 直接当成 br 用,后面跟个 parserFail 来保证质量,相当与在分支里写断言。

toMust 用来应对快捷需求的情况
依然是开心的一天。
Kotlin 可以用 sequence,ParserKt不是handle这种情况的,虽然可以写