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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
我不该废几个小时说这么多的,反正各位看官不感兴趣。 #statement #life #dev
不管费多大力气,以后被自己遗忘意义又有多大呢…… 虽然我对同一类问题的描述也在越来越好。

如果我有个个人博客…… 不对,认识的大佬博客都无人问津,不管他们前端技能多好或者性格多热情。 如果他们的性格弱一点,反而会被最普通的工程师,甚至其队友轻视。

当个「大佬」,不管多热忱都只是自我陶醉的话,好像还是默默做项目、作高冷不食烟火的姿态比较好呢,不过我是不会变成那样的大佬的。

我不知道大佬的性格高冷和他们的「开发成功」有没有关系,是因为高冷所以成功的多、还是因为成功的多所以高冷? 但我始终乐意与别人分享我的经验和知识、努力提升自己的表达能力 让更多人看懂,抽点时间出来,不管有没有人能学到。

不知道专门研究这些东西的学院派大佬看到后会怎么想,不专业?不尊重学术?异想天开? 但我觉得一个问题真正的价值在于被人知晓、被人理解,仿佛它是有生命的一样;而不是与生俱来就有价值要让人为它头疼和浪费时间。如果有问题没人解释,那么较次的解释也可以接受。存在是第一意义。
duangsuse::Echo
呃... 既然都说到这一步了就顺带讲一下我之前关于 动态作用域/词法作用域的见闻,虽然我知道没人感兴趣的。 动态作用域(dynamic scoping)就是你们能想到的,末端是全局作用域的嵌套表。 理解为栈,当前层的key被赋值、最顶层的表里的key被取值,所以栈帧销毁后解析会有不同的结果。 动态作用域没什么问题,也被用于诸如(嵌套命名空间)类型名解析的地方,除非函数可以作为值——比如 (set! a 1) (def get-kst() (lambda () a) ) (def main(a) (get…
不过做这种事大概也不是没有意义的,这一次我发现了实现 dynamic scoping 的做法靠环境表复制也可以实现 lexical scoping 和闭包,所以说动态静态的 scoping 之间并不是完全隔离的,它们的本质都是命名覆盖,动态作用域的问题仅在于运行时在调用栈上的解析使得变量名唯一性问题显现,只有环境闭包一个区别,竟然是这样…… #PLT #cs #ce
This media is not supported in your browser
VIEW IN TELEGRAM
有些东西,其实本来就只是那个/那几种意思而已,可是说得太细又不好看、太粗略怕各位去看别人文章和「业界标准」的时候get不到同义词。

同一件事情、一件直白到可以隐含的事情,不同的人讲会有不同的说法,我也不知道该怎么说。
http://www.yinwang.org/blog-cn/2017/05/25/dsl#动态逻辑加载
草,这个玩意放 Kotlin 里就是一个组织出 typealias Predicate<T> = (T) -> Boolean 的解析器,其实根本没必要做成独立解释器甚至逻辑关系式编程的……
duangsuse::Echo
呃... 既然都说到这一步了就顺带讲一下我之前关于 动态作用域/词法作用域的见闻,虽然我知道没人感兴趣的。 动态作用域(dynamic scoping)就是你们能想到的,末端是全局作用域的嵌套表。 理解为栈,当前层的key被赋值、最顶层的表里的key被取值,所以栈帧销毁后解析会有不同的结果。 动态作用域没什么问题,也被用于诸如(嵌套命名空间)类型名解析的地方,除非函数可以作为值——比如 (set! a 1) (def get-kst() (lambda () a) ) (def main(a) (get…
关于 Kamet 里 val/var 和 let 的区别,本来我的意思是要除掉 let 的,但它的语义也的确不同
最开始, Kamet 只有栈上局部变量 var 和 const var (即后来的 val)
后来 Mivik 可能是发现 fun add1(n:Int) { val res = n+1; return res } 完全不需要实际栈上分配而可以内联,于是又新加入了 let

看起来 var / val 和 let 是各司其职、其区分无可厚非,我相信这种做法仍是不好看的,并且 val 应该默认具有 let 的语义(Kotlin 一直为最常用的语法优化简洁性)
只有在定义聚合量的时候 val/let 的区分才有意义,因为标量都可以选择让 LLVM 自动处理寄存器分配(或溢出到栈上)

对于 C 系语言来说,没有 GC 、struct 数据的指针是暴露的,但是返回在函数内局部分配的指针是错误的悬垂指针,局部分配一个 struct 却要从堆上复制是无意义的,
val 「定义栈上变量」的语义除了 no initializer 外只有调用构造器(因为要局部分配初始化)的可能(当然 Rust 式的 {} 构造器也有可能...)
https://github.com/Mivik/kamet/blob/master/src/main/kotlin/com/mivik/kamet/ast/DeclareNode.kt#L58
所以可不可以把
val x: [Int, 5]
let first: &Int = x[0]

替换成
val new x: [Int, 5]
val first: &Int = x[0]

呢...
duangsuse::Echo
呃... 既然都说到这一步了就顺带讲一下我之前关于 动态作用域/词法作用域的见闻,虽然我知道没人感兴趣的。 动态作用域(dynamic scoping)就是你们能想到的,末端是全局作用域的嵌套表。 理解为栈,当前层的key被赋值、最顶层的表里的key被取值,所以栈帧销毁后解析会有不同的结果。 动态作用域没什么问题,也被用于诸如(嵌套命名空间)类型名解析的地方,除非函数可以作为值——比如 (set! a 1) (def get-kst() (lambda () a) ) (def main(a) (get…
我想这个泛型参数推导其实到底是我想复杂了吧…… 总觉的要用描述式编程来推导类型参数
仔细想想,一个局部 MutableMap 就可以了。 大家把自己关于某未知类型 <T> 的信息聚集到一块不就推出来了,何必用相等性双边推导(unification)来做呢....

class A<T>(val x: T)
val a = A(1)

直接像 Mivik 一样弄一个 TypeParameterTable.scoped , 让构造器参数的 x:T, T=Int 往表里一放 , 同时也解决了递归无法推导的问题
fun <T> extract(a: A<T>): T = a.x
extract(a)
同样是把 a:A<T>, T=Int 往表里一放就推出了 T,真的很无聊欸...
fun <T, R> run(a: A<A<T>>, op: Function<T, R>): R = op(a.x.x)
run(A(1)/*A<A<Int>>,A<Int>,T=Int*/) { print(it)/*(?) -> R=Unit*/ }
也同样很好推导,所有参数的类参名与实参一 zip,往当前表里一放再检查一致性,也不存在需要赋值 op的 <T> 的问题,用表惰性取值已经解决了

(难怪信息不够时 Kotlinc 只是简单的提及 no enough information, 因为这个算法本身就很简单...)

这么简单的推导算法那些 Javac 设计者竟然不弄完整?反而做成只有 "diamond operator" 的形式,他们真是弱智?!
This media is not supported in your browser
VIEW IN TELEGRAM
推个 Generic 类型还用相等关系解构去看什么 state var intro goal ,看来我受到的误导很深。
原来不必建模成相等关系然后 unification ,只用 table 也能做到啊,真的是把 information 聚在一起就能推出来,是我智障了。
(当然用相等关系但不必实现关系式编程也可以, Box<T> = Box<Int> 一样能推出 T=Int... 但基础组件写来麻烦一些)

Kotlin 里好像也是只有 fun 的类型参数能推导,而 class/interface 必须是显式写出的
不过今天填志愿,就不多说了。一般这种 "Talk is cheap" 的更新也不常见,改天我写个 bot 导出 markdown 发知乎去。

提出一个编程方法,没有任何特色而我将它用于无草稿设计,优点是设计小脚本很方便,称之为 LSPA(Lifecycle, structure, program action. 主要在 "LS", 加 "PA" 是为了好记)

比如小明有一个 pandas.DataFrame 要从网上搜索下载网页,测试关键词匹配数来生成 it["rank"] 列用于排序,这里就有两个 lifecycle: scrape-pages, gen-rank
分别使用 [psearcherr, requests, bs4], SavedFile(name, classifier), curl, findXXXLink 和 findMatches, xxxMatch, len 等函数来构成逻辑
df["rank"] = [sum(map(lambda tag: len(findMatch(SavedFile(name, tag).readOr(""), ["index", "a"]))  )) for name in df["name"]]

所以在整理好提纲以后,脚本编写会容易一些,但对大点的设计还是要逐步细分设计的。
用这种方法后可以将程序分为最基础的原理算法、某 lifecycle 里的功能点两部分(比如 scrape-pages 里可以指定 df[df["name"] == start:] 爬取行起点),方便进行隔离的建模
structure, program action 只是附加点,一般小脚本里的 structure 和控制流什么的不会太复杂
This media is not supported in your browser
VIEW IN TELEGRAM
from types import CodeType
c = CodeType(0,0,0,1,64,b'd\x00S\x00',(1,),('',),('',),'','<module>',1,b'',('',),('',))
eval(c)
嗯……找到问题所在了。 双向转换没写好,现在可以序列化缓存代码对象了。
完成了! 不过不知道是 pickle 性能高还是 struct 性能高... 反正我懒得写 pickle 版(花好大力气完成的复古
%timeit codeSer.loads(codeSer.dumps(c))
34.6 µs ± 103 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
from pickle import dumps, loads
%timeit codeSer.loadItems(loads(dumps(codeSer.dumpItems(c))))
25.8 µs ± 405 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

还好我写的抽象层有支持…… 就知道跑不过 pickle ... 这个变态腌黄瓜。 ☹️
This media is not supported in your browser
VIEW IN TELEGRAM
不想删啊…… 早知道用 struct 不合适的,而且它是个贼老的东西了,为了支持动态长度字符串我还加了 hack
性能渣是肯定的... 还是换 Pickle 后端好了
腌黄瓜实在是太过分了,我好不容易给 struct 弄好字符串支持的
早知道就不给弄了,草死了