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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
第一次知道原来大佬也有不重视代码质量的时候(话说我是有点强迫症吧……)
20 行要我就不会用 o.addXXX(cfg.build() )

opt.initArgs("""
c client-port language-
s server-port language-
a client-host ?language client hostname, default localhost
i interactive ?start the Arend REPL
""".trimPadding())


我对代码的追求,慢慢也从仅排版整齐上,变成了空格排版项目范围内语义一致、重视代码简洁性和可配置性;想想以前的我看见现在的代码,估计会觉得很难看吧 🤔

fun Options.initArgs(code: String, sep: String = "-") {
addOption("h", "help", false, "print this message")
code.split("\n").forEach { line ->
val (s, sLong, desc) = line.split(' ', limit = 3)
val opt = Option.builder(s).longOpt(sLong)
if (sep in sLong) opt.hasArg().argName(sLong.substringAfter(sep))
opt.desc(if (desc[0] == '?') { opt.optionalArg(true); desc.drop(1) } else { desc }.replace('-', sLong.replace(sep, ' ')) )
addOption(opt.build())
}
}

运行时开销又高了😂 不过总体看处理了 3种 case (normal+1param+optional, 交织的不算),还是挺清晰的
duangsuse::Echo
https://github.com/ice1000/arend-language-server/blob/88dd2e94ea7ae564a743d349b93487dd5aa4b5f8/src/main/kotlin/server.kt 草,原来冰封那么厉害也没有写自己的 Argument Parser... 我还以为函数式爱好者都痛恨 (org.apache.commons.cli) 需要 (opt as Options).addOption(Option.builder("i").build())…
#Java #Kotlin #GitHub #project #suggest 评论一下我之前开发的 ArgParser 😂
是个好东西,对命令行参数的建模也很好,就是 addHelpSubCommand() 这样的帮助函数,没有考虑到应用的需要,应为 addHelpVerCommand 不对,这个是显示子命令树结构的... 那个 -h -v 的也应该有,但可以另加
还有,生成命令行补全的代码也该加

存在的一些问题,包括强类型约束过于严苛(为此还有 ArgParser4~1 的泛型), 以及 subcommand&formatter 参数实现未测试的瑕疵("All tests passed" 但复杂了 我不敢保证) 😂
(Apache: 你敢和我比?🌚强大吗? 还有 "<!s #d"fmtstr...)
谈谈 "both [src...] [dst] and [dst] [src...] are supported" 是怎么实现的吧
我们的解析器是流式的(因为框架很重视不同甜度需求的复用性,它是一层层建起来的,其根基 SwitchParser 就是基于状态机构建输出数据结构的)

所以实践上 [src...] dst 里你怎么知道 srcs 不能把最后一个 dst 也解析了(看起来 dst 也可以理解为 src 的一项啊) 🤔? Py 的 argparse 也支持这样(但我不清楚它的架构细节),总之没有一些较 dirty 的 hack 是比较不容易的。

一个即得的技巧是,记住上一次读的 list ,然后读 dst 时从 vararg items 里“偷” 一个项目出来,末尾有 N 项就“偷” N 次。
另一个技巧是寻找 vararg items 的 position ,解析时直接就算 srcs 有多少项,取了跳过 (有点类似 Lua 虚拟机对不定长参函数的编码方法,但这种方法可以做成支持多个 vararg 的不知道有啥样用)

ArgParser 的解决方法比较骚,因为它支持 unparse (backRun) ,换句话说它可以先用无问题的 [dst] [src...] 解析(通过动态构造解析器),再把整个 items 拼了转过来
没有那么高级,其实只需要把参数输入和解析结果,共反转两次就够了 🌝(不过依然要用到 backRun 😂
这是为什么呢? 因为我们必须先检查参数是否合法,并且取得其中 item arg 部分…… 但如果你的代码没有用到 reverse, 相应 backRun 逻辑是不需要的(只是即便这样 progurad 等工具也不知道它可以 delete 掉 (x
#tencent #Haha 😂 想到华为之前挺的那个啥 Linux OS
Forwarded from 某10
&'a ::rynco::UntitledChannel
https://twitter.com/magicxqq/status/1351032008533831684?s=19 微信毒瘤特点++
#cplusplus #linux #apple #China #tencent #wechat
相应肇事代码: [lib] [app] (by dlsym(RTLD_DEFAULT,"X") )
奇怪的是,在这些代码 is_debug = (sym!=NULL&&*sym!=0); 里我没有注意到不兼容无此符号的问题,估计是 dlsym 设置了 errno 导致运行时错误。

已经有人开了修复 PR (@NeverBehave@metowolf 对此表示 😂)
我感到非常奇怪, WeChat 凭什么去影响上游,让别人帮忙擦屁股? 😡
影响力就是这么大!(指文化输出)
duangsuse::Echo
#cplusplus #linux #apple #China #tencent #wechat 相应肇事代码: [lib] [app] (by dlsym(RTLD_DEFAULT,"X") ) 奇怪的是,在这些代码 is_debug = (sym!=NULL&&*sym!=0); 里我没有注意到不兼容无此符号的问题,估计是 dlsym 设置了 errno 导致运行时错误。 已经有人开了修复 PR (@NeverBehave 和 @metowolf 对此表示 😂) 我感到非常奇怪, WeChat 凭什…
为什么人家要修:估计是果粉报给 Apple 了,人家一生气就改了 libmalloc ,反正多个符号也没问题 🌚
为什么人家骂 weird : stack_logging_enable_logging 实际就是“你怎么证明你活着”,本来被使用了就是 enabled ,何必搞什么 _enable_logging 呢?
#windows #security #chrome #web Win8 无效, Win10 蓝屏重启
Forwarded from RWTG9Y4's STDOUT
好消息 好消息
现在你的 Chrome 可以直接造成系统 BSOD 啦
立刻在地址栏输入 \\.\globalroot\device\condrv\kernelconnect 领取蓝屏大礼包一份
* 就算是放在 <a href/> 里的链接也可以造成蓝屏
duangsuse::Echo
https://github.com/ice1000/arend-language-server/blob/88dd2e94ea7ae564a743d349b93487dd5aa4b5f8/src/main/kotlin/server.kt 草,原来冰封那么厉害也没有写自己的 Argument Parser... 我还以为函数式爱好者都痛恨 (org.apache.commons.cli) 需要 (opt as Options).addOption(Option.builder("i").build())…
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望
虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。

这里也有一个 initNewFrame + listen keyEvent & StringBuilder & draw text 的示例
总的来说是很重视性能的一个 JNI 封装, 利用了Critical Native ,从不在 Java/C++ 之间传输 primitive (array) 外的数据(这是十分推荐的);也会处理 String/std::string 缓存的问题(感觉管得有点宽,应该解耦了) 甚至可以自定义封送 转换函数
用了 intFlag @MagicConstant@Nullable 有好的 IDE 支持

看了一会想点 star ,突然发现我 GitHub 好像被 @ice1000 ban 了,现在还没有解除一样
可能是以前冒犯过他吧,觉得应该解除了啊,唉🌚
找了半天没找到他之前发的 JLine ,找到这个 ,代码质量……
duangsuse::Echo
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望 虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。 这里也有一个 initNewFrame + listen keyEvent & StringBuilder…
吃饭的路上(最近有点劳累过度了,思量着 ANSI BadApple 赶紧结束休息几天吧),谈到所谓“优雅性”,想了一下 ParserKt 新 LexerFeed 的问题,感觉很 complicated ,流对象的各种属性真的不好办

首先是说这个给冰封提到底有没有意义的问题(毕竟 PM 冰封是一个比较要心理准备的事情,心理难度比与 Python 红姐、九月姐 谈笑风生不低多少),最后结论是有。

虽然 jimgui 的本意未必是做“定义式”的 GUI 框架,更像是学习 JNI 设计,而且 Kotlin wrapper 很可能会有好的接口,技术交流也是不应有太多压力的。
TkGUI 的代码生成方法利用了 Python 无编译期/运行期,虚拟机相关组件基本可用的动态性,以及动态类型;很难(或者说意义不大)移植到 Java ,但我的本意是 GUI 可以这么写, ImGui 的做法可以说是业界惯例(就我的观察, GTK, Wx 的大部分封装不需要为子控件选择 parent, 但没有一个支持树形代码定义一个视图,即便其语言有足够表现力),Java 的 Swing Frame,Panel 和 Fx Stage,Scene,Group 都必须用 mutate 对象的方法「创建」模板化的视图树(当然这是过程式的自然映照,无可厚非), Qt 和 C#, VB 有 uic 这样的 code generator ;而 TkGUI 的 way 更像是 parser combinator 那样,尽可能少用外部工具,直接在语言里组合。

这个 way 就是一句话,“优美的代码能直观地反映它所处理数据的结构”,程序结构和数据结构相互照应、谐调统一,虽然会有额外开销,但一件事情只有你重视了才能找到各方面的最优解决办法,否则就永远只是传说。

再谈 ParserKt 的问题,其实最初版本相较于一些同类已经可以算是优雅了(当然离我想的还更远)
几个月前的重计划里包含了“削除 Parser 里 Lexer 相关代码”的改动,可以说是解决了我心头一厌(很多 PEG 生成器都逃不开跳空格注释的问题,要么然写文法里,要么然走 lexer/parser 的老路,要么然可配置性不够好,这是比较草的,因为我觉得在 a b c “按顺序”模式里默认插跳空格的逻辑是接近正解的)

具体实现还算好, Lexer/Parser 的区分、 Token 而非 Char 流的存在,核心原因是空格和注释对语法结构是无效的——最好能无视,免得解析器混杂
scannerless parser 很好,但跳空格其实有更容易的解决方法——为 Input stream 添加 filter ,到底还是 java 那一套自由组合的 stream 最好,连 skipped whitespaces 以及 AST element spans 它都可以往 Map<K,V> 存储好了,这就同时解决了 AST data class 不好写的问题,在不必使用这些信息时,也提升了性能,就从根源上解决了许多联带(代码复用、类型冗余和构造器隐式参数、分词解析器如何相互协调的)问题。

核心思想容易,实现上也有些问题—— Lexer 和 parser 在最近的语言里越来越模糊了,你可以看到 KotlinLexer 里会处理一些嵌套问题(就需要 push/pop state number 了),而且 >=fun():P<T>= 的区分也使得它必须识别一些本该由文法处理的模式——在过去这是不可想象的,C 的词法规则相当简单

这么做势必造成计算力的浪费(分词器和解析器对同一份数据做了类似的动作——检查它的嵌套结构),以及编程的冗余、重复代码,是应该努力避免的。

解析器与“分词器”之间的交流,显然是 parser combinator 的优势——它们的结构对程序员是完全透明的,可以自由定义、随意组合,让 Parser 去驱动其输入流上的 Lexer ,告诉分词器现在是什么状态,需不需要跳空格(例如 "" 里就不能跳);分词器是一个针对 Feed 流的状态机,本身也是一个 Feed ,而 onChar 的时候被动进行状态转移,就可以 filter 掉那些解析器不想看的字符,同时也能选择性地保留(如语法高亮) 的数据,一举多得。

有的观众就会问了:这么好的方法,比你高到不知哪里去的聪明人可多了,怎么就你想出来?
首先,不能说是没人想,要看编程实践怎么用、怎么组合这些技巧,不是说你去做了,效果就真的能像想象的那样好
其次,如果你没把代码重写 9遍,也容易被 Lexer/parser 和 scannerless 的那群既有实践误导,以为必须有 tokenizer ,或者流只能是一层,不能有“滤过”操作的
如果 LexerFeed被动性[2](非阻塞,要不然无法共享 string 等词法的定义)以及 Parser 对其的主动性(传递在解析词条类型号)不能被保证, 许多人对输入字符序列的抽象不够灵活(万恶之源),使得他们不能够发现这一点。 (所以你在编程的时候,记得重复的少写一点、稀奇的功能特性多写一点,说不定还能帮助你对程序模型整体的理解)
(这种设计也很好的发扬了 ParserKt 的 one-pass 设计,而 C 系语言 // /* 注释与除号的区分早有给 InfixPattern 扫描操作符的 TriePattern 专定子类可轻易完成,PKT 的组合性不加盖的)

但这个封装有很大问题—— ParserKt 最初只有 Feed { val peek; fun consume() } ,不像一些 nextChar()curChar() 数据视口不一致、命名迷惑的框架,它的流模型只允许程序员着眼一项(最本质的问题),结束时抛 Feed.End 异常
尽管这是根基(SliceFeed, Iterator/ReaderFeed 子类),它也是不切实际的,所以很快有了 Input(s: Feed): Feed, SourceLocated, ErrorHandler [1],以及一大堆 Feed 上试着 (this as Input) 的扩展函数,允许解析器带行号,尽量减小开销(统计行号信息是要在 Char 输入上,而一些输入根本无需 Input 的一些成员)
而那些接收 Input 的 Input ,就只能用一个代理(delegate)类 Input.By 去 proxy 这 underlying stream 实现的一些特性,这种问题严重后有点像“责任链”的字面含义——不断尝试 unwrap 一个 (可能是Input的)Feed ,寻找某个 trait 的实现者。

如果说你组织流嵌套的方法是手工的,应该不需要滥用多态去做“动态类型”,又或者是自动的——真的到那种“可组合”的地步吗?

最后我觉得,还是做 LexerInput(s:Input): Input.By 比较好,这样 LexerInput(Input(s=SliceFeed(Slice("wtf") ))) 这样的二层就会成为必要的组合法,如果需要其他层,则不能打破 Lexer 需求 Input (SourceLocated) 的类型, 还是取消这样的限制吧…… 真不知该怎样解决这问题 #parser #parsing #learn #Kotlin #project #suggest

[^1] 现在我更倾向 Input: Feed, FeedControl, SourceLocated { val states:Map<String,Any>; val onError; val isCompleteRead:Boolean }
isCompleteRead 是重新建模的(结果存逆波兰栈的)算符链解析器需要的,在非 complete read 时,可以像 Lua 一样直接进行简单的常量折叠,否则不仅不能折叠,还要存语法元素行号、前部空格等(重现原文所需的)信息
[^2] 其实我理解错了,这也是因为 LexerFeed 最开始是能自动识别底层输入的状态机,上级请求字符时肯定是要 blocking consume 直到非空格字符的,所谓非阻塞是因为对非空格单个字符它照样要处理状态转移;现在我倾向把它做成“能暂时屏蔽的自动 ws skip”一些,因为这才能真正统一复用文法/词法规则 ,虽然那样就没有花里胡哨的 List<Triple<Char,Int,Int>> 了(毕竟有效性在那)
duangsuse::Echo
https://github.com/ice1000/jimgui/blob/master/core/test/org/ice1000/jimgui/tests/Demo.java ... 看了以后我对冰封哥的审美有点失望 虽然这只是一个直接的重写,我看出 jimgui 没有比 ImGui 本身更高的封装,它仅以 add container 的方式暴露了 tree ,这不符合之前写 TkGUI 时我的期望。 这里也有一个 initNewFrame + listen keyEvent & StringBuilder…
被冰封有理有据地怒斥了一顿…… 下次我还得委婉点,不对,得先对相应框架、库去学习一个 ,还得仔细对下稿子,不能搞错客观事实
冰封还说我对
Optimization for strings. That jimgui by default uses an inefficient way to convert java.lang.String into byte arrays that C++ is happy with. You can customize the string-to-bytes function yourself by using org.ice1000.jimgui.util.JImGuiUtil.setStringToBytes the default caching JImGuiUtil.cacheStringToBytes(), or use the more efficient alternative to java.lang.String -- org.ice1000.jimgui.JImStr, which is supposed to be created as global constants.
的理解是错误的,在此斧正注明一下

此外冰封最后说要把我 tg 也给 ban 了,可能是真的,也可能不是认真的 😰
duangsuse::Echo
被冰封有理有据地怒斥了一顿…… 下次我还得委婉点,不对,得先对相应框架、库去学习一个 ,还得仔细对下稿子,不能搞错客观事实 冰封还说我对 Optimization for strings. That jimgui by default uses an inefficient way to convert java.lang.String into byte arrays that C++ is happy with. You can customize the string-to-bytes function…
第二人格🌝:等你把新 ParserKt 搞出来,再写几个编译器、语言工具出来,对他们不就有底气了吗? 何必虚心提出交流,直接上去就是一堆 LiteratePy 降维细解博文实操代码,各种领域都加上,哪怕是不准确的,也能倒逼他们出来辟谣,有利于他人学习,岂不美哉?
#dev #plt #statement
>你不要再到处提我的名字了,并不能显得你很高大上
<“我觉得自己最大的特色就是并不想让任何人觉得自己高大上,但想让深奥的技术更亲民而已”
<如果说我能离开你们发展这么久(当然我并不会道德绑架自由人),却偏偏要靠着你们的名字骗小白的话,那才叫低劣呢 :x

但是,我会一直谨记这句话,不管现在能不能成功,但它是我的态度,就像三年前一样。我希望能一直这样。
一个人的名字多么狭隘,要做,就要做大的。
刚才我私信里说一定会研究下这个库(真是没事找事),只能先写下这个示例了
#Java #code
UI.render(Application().title("table").width(1200).height(500)) {
val colOpts = Column("Options").widgets(/*rendering widget instead of row-object property*/
Button(/*auto-id, must*/).text("OK").sameline(true).onClick { it.text((it.getData("rowData") as User).name) }
)
Window("w").fill().children(
Table("tbl").globalFilter(true).cellEditor(true).rowsPerPage(10).columns( //gfilter, cedit
*"name age country".split(' ').mapToArray { Column(it.capitalize()).field(it) }+arrayOf(colOpts)
))
}

TkGUI 目前无等价(Table 等 Model/View 建模到底如何做还存疑,已有 TreeWidget 可以做无 button cell 的),但有增添可能。
是很好了 (我猜是不是用了代码生成呢?),如果要提一点激进的建议,我觉得 Box/Size 这种模型可以尽早使用 Application(title = "a", size = 1200 xHeight 5000) ,此外可以 Lombok 省去构造器 new,当然如果真加 Kotlin 的话绝不能用 infix fun

不过我可以搞个超前示例,如果以后绝句写出来了,会是这样封装:

引记法 瓷 「配」
引全 瓷.元素配置
物 示例:窗体应用("table", 宽高(1200, 500)) 为
晚成的量 主表:表单
实现的事 布局() = 表单(
提取自 ("name age country"切分以' ')映为组再末追(选项列),〖名〗表单.列(名取大写“不是全大写”、项=名)。、
全局过滤=真、单元可编辑=真、每页行数=10
) 名为(主表) 配填满格
其中,量 选项列 = 表单.列("Options"、钮(内文="OK")配同行 点击时,内文=(上级数据作用户)的名字。 )

散的程度没有 ImGui 高,没有 UI.render( 和 Application,我觉得散是有好处的
感觉极其生草啊……
This media is not supported in your browser
VIEW IN TELEGRAM
吃饱了没事干,去研究这个像 builder 但却非常函数式的框架,因为它性能高而且定义式。
我们还是要…按照这个基本法,按照《中国民众健康暂行规定》…去规避…… 12点就睡大觉,没关系的
This media is not supported in your browser
VIEW IN TELEGRAM