duangsuse::Echo
413 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
#Rust #Haskell 反正我现在看 Rust 语法设计也不见得多好…… 但是总还是少点冗余
具体说一下, #Rust 不是 #OOP ,但支持 OOP 写法(成员访问、调用链等)

Rust 不需要 Java/ES6 的模板 constructor ,它是 struct A { fn new() -> A } 的 A::new 命名空间+函数名惯例+#Haskell/JSON 式 Record 构造器 模式,写 impl A {} 第一参关键字 self:&Self 即可(完美替代 #cpp )。方法解析支持静态和 fat pointer 双指针 (vtablePtr+refPtr)

我不满意的地方可能是它的语法太随性(长短不齐、太像数学)吧,而且宏系统的各种变量/类型名也不大优雅

如果要我把 Rust 的设计风格与 Java 的相比,我更讨厌 #Java ,因为它是没学问装逼(冗长),而 Rust 则是过于老学究了,尽管社区很友好。

#Kotlin 是我目前唯一满意的语言设计,虽然感觉实践上 scope function 和 fun= 简写会被一些人滥用。
fold.kt
1.1 KB
#Kotlin #OOP "小王 老猪 阿司马 某A君".split(" ").map(String::length).fold { reduceAll(::minMaxer, ::averager) } == arrayOf(2 to 3, 2)
Forwarded from duangsuse::Echo (duangsuse)
fold.kt
1.1 KB
#Kotlin #OOP "小王 老猪 阿司马 某A君".split(" ").map(String::length).fold { reduceAll(::minMaxer, ::averager) } == arrayOf(2 to 3, 2)
#js #DontKnow 原型链:(感谢 @JackWorks 提供相关信息)

访问语法都是动态解析的,比如 x.prop
x["prop"]
就是
x.[[Get]]("prop", x)

ES 里一共有五种不同的 [[Get]] 实现,分别是
- 普通对象 [规范]
- Argument 对象(你们今天应该不会用到了)
- 类数组对象(数组的特殊行为就在这里)
- 模块对象(import * as Mod 里的 Mod
- Proxy 对象(reflect proxy 全 delegate)

此外, Object.getOwnPropertyDescriptor(o, k) 可以获取可配置 enumerable, writeable 等属性的配置对象
Object.[get/set]PrototypeOf(o)
o.__proto__ 是它的「超类虚表」

[[Get]] 过程的 Receiver (第二参数)很重要,如果没有这个 Receiver,基于原型链的 OOP 其实是做不起来的

原来是往 proto 上找属性!
这就解释了 Array.prototype.map 之类的东西

parent = { method() { return this; } }
child = {}; child.__proto__ = parent;
child.a = 1; child.method(); // 返回自身
最简单的解释是, Receiver 就是属性访问的时候最上层的那个对象,会被当成 this 用。
因为在这个算法里你可以看到,Receiver 是跟着递归一路传递下去的

原来是 o["RESOLVE"](o.prototype, "attr", receiver=o) !(当然,肯定是先查本地,然后才查 prototype
本地如果有就不会查 prototype 了

明白了,和之前写的 LuaOOP 很像,都是层叠属性查找

“ 大佬能交换下原型链相关知识吗
之前看加 Mixin 好像是说把 prototype 除了哪两个属性的什么全部复制一下
#Python#Ruby 的情况我都了解, Py 是 mro() 链查询, A.wtfa.wtf 都是往 class A 找成员,后者实质是 type(a).wtf(a) 所以得到 bound method ,而直接 A.wtf 就是 bind 操作
@staticmethod 直接不收 self ,不需要 bound 所以可以在类和实例上用

https://paste.ubuntu.com/p/tJv7QpSjGt/ liuil-util 的 #TypeScript mixin.ts 重写
duangsuse::Echo
#js #DontKnow 原型链:(感谢 @JackWorks 提供相关信息) 访问语法都是动态解析的,比如 x.prop 或 x["prop"] 就是 x.[[Get]]("prop", x) ES 里一共有五种不同的 [[Get]] 实现,分别是 - 普通对象 [规范] - Argument 对象(你们今天应该不会用到了) - 类数组对象(数组的特殊行为就在这里) - 模块对象(import * as Mod 里的 Mod) - Proxy 对象(reflect proxy 全 delegate)…
让我想起了,那些手写 new/apply/call 的题目 #js #plt #oop
很多人说的 oop 是 Class-oriented programming
而 JavaScript 的原型链才是正宗的 Object-oriented programming(

function X(){}
X.prototype.a=1;
new X().prototype === undefined; // 但 __proto__ 就是 X
Object.getPrototypeOf(X) === Function.prototype
prototype 只是个(被特殊处理的)普通属性
平时说的原型链指的是 obj.[[Prototype]]

a.f()
相当于
f = a.f; f.[[Call]](a, [])

“ 为什么要用 ecmascript 规范里的(原语)写
因为 a.f.call 是从 a.f 往上查了原型链查到 Function.prototype.call 之后,它 也有可能被覆盖掉
Reflect.apply(a.f, a, [])
也能覆盖: globalThis.Reflect = new Proxy(Reflect

” 我就很奇怪为什么我在 constructor 里 this.prototype === undefined

x: 工厂函数
x.prototype: 造实例的原型, new 出来的东西 __proto__

Object.create
, Object.assign
Object.defineProperty
#Kotlin #design 提问!怎么写 matcher 库呢?

你需要了解如何写可组合的操作,这里是 predicate: (T) -> Boolean ,当然实际上必须维护可阅读的结果报告(String path, Map mismatchs)

接着,考虑是 val 还是 fun,用不用 receiver 参数或带 receiver 参数的 Scope 闭包即可。

组合很简单,用函数的闭包(即 #OOP 对象)拼凑实际表达式
1.match { all(eq(1), lt(5)) } 其中 lt 是 lessThan 的意思。
const eq=a=>b=>(a==b), //lt也是一样模式,除了(b,a)=>(a<b)倒个语序
all=(...ps)=>x=>{ for(let p of ps) if(!p(x))return false; return true; }


咱可以看到,这个「高复用」办法本质只是在隐式化、拼凑参数罢了,其实 ==,!=,<>,in 等二元逻辑算符的引入都是预提供一个参数,等另一个参数 ,而 all, any, none (&|, !|) 则是在组合 Predicate 类型,用 for 循环解释 && 等算符短路(即惰性)求值的语义(any,all 等列表处理操作本是如此性质)。

当然,它们本身也是可被组合的,就像程序结构本身一样;但,原来十行代码的东西就只用写一行了,多快好省。

如果只是这样根本没必要单独开项目,反正计算开销小,可以取消 all 等组合器的部分求值,即便已知 mismatch 也只是存到一个结果报告(Map+path 足矣)里继续测试,这只需要让 all matcher 能知道自己的「路径」并且给子项们接上「新路径」。

只需把只能 apply() 的 function value 变成带构造器和 .var 的 interface ,在构造器里给子项进行 .path= 的「注入」隐式提供其路径,它之后的生命里全复用即可。
不过,这么一来就变成 interface Matcher { var name:String, fun test(x:T, m:Map<String,ErrMsg>) } 了,不需要给父组合器提示返回值了呢。
不过,这也照应了程序本身树穷尽遍历的性质,不再是逻辑表达式的「解释器」了。
Forwarded from duangsuse
https://t.me/dsuse/16941 早上没起床就写了点相关知识……

嘛其实我觉得 mvc.perform(httpOp).andExpect(matcher) 挺冗余的, mvc.expect(arrayOf(httpOp to matcher)) 合适点

status=>ResultMatcher { AssertionErrors.assertNotEqual("status", status.value(), it.response.status) }

mockMvc.perform(post(path)).andExpect(status().isNotFound) 不能 Matcher.not() 是肯定的,如果要的话需要更改最下层的(==)命题,直接否决(不对…… ParserKt 的问题是 Repeat.not 的肯定要 rewrap ,但是这个的数据类型没有不同(不对,这个靠 ErrList 依然会有变换后否决错误信息缺失的问题……

如果让动苏来设计就不会有这种问题
duangsuse::Echo
Photo
#Learn #OOP #js #design #Java #Kotlin
duangsuse:
大失败,不会写了;第一次还觉得需要 RingBuffer 或者双指针维护缓冲器那样……

其实根本没有那么麻烦, post 的时候带上 queue index ,全部完成右移视口 offset 就够了,如果没全完成右移也不行
简单设计复杂化

许久没有编程的动苏眼高手低到了这样的程度,不行,一定要写出来刚才那个的核心逻辑😡

……草,竟然真的可以用了,虽然没测试 原来 runtime.Port 真的像 channel 一样要 sender自己 onMessage 也能收到,所以要先 verify 吗

基础封装的逻辑就是封装 channel , create server 可选, client 一定;兼容了 DOM postMessage API

假定 Function 的 que 无法共享,利用 seqNum (传输侧别名为 no) 指代响应目标,然后 que 本身利用 offsetL 压缩一下,不会一直增长
核心部分 20 行

仔细想想这个封装的确很有必要,总体 post/onMessage 请求一次 backend 是 callback(proc(msg)) ,C/S 两边都要 post,onMessage,msg,post 还难复用信道,call 了服务端处理完还要尝试按原名回调,容易重复标识符数据。

Jack Works:
来,把异常处理也加上

duangsuse:
Uncaught DOMException: The object could not be cloned.
不得不想序列化变形的办法…… 而且 JS 还是弱类型

好吧,好像需要一个完整的序列化方法,这个方法必须介入 sendMessage 数据来允许保留类型信息,如果不止要存留 Error message 的话 🌚

Jack Works:
到最后你会发现你重新发明了 JSON RPC

所以我把我的实现改造成了 JSON RPC 做成了通用的库

duangsuse:
serialize 本来就应该是框架层做的,而且它也只需要暴露 ser() deser() 两个函数而已
我们只不过应该在框架上写个十来行的小程序就够了

Jack Works:
我也是这么设计的啊, https://jack-works.github.io/async-call-rpc/async-call-rpc.asynccalloptions.html

duangsuse:
中国开发者越来越难了, github.io 都不能用了 #China #net #Freedom

以后写个软件第一关过政审第二关过苹果 Steam 的审,层层加码,服!

duangsuse:
累死了,反正能用就行
格局小了,我本来准备写 DOM 动画的,又鸽子了,再鸽就溢出了……

又到了各种 push 不上去的时间段,中国的网络环境。

Jack 那个我是真的摸不清,骨架太大了,重写人的脑力也是有限的(当然 typing 应该看得懂 就是各种 scope feature 看不懂),知道 onConnect,disconnect 这些 API 也不好分析
不过好歹是能用一个,虽然肯定有性能开销了

Jack Works:
里面逻辑复杂但是外面接口简单啊

duangsuse:
动苏的标准是从内到外没有业务主干外的代码,如果有就作为插件嵌在骨干外…… 总之就是一句话,强调最根本最必须的算法 #statement

Jack Works:
你只要写一下怎么收发消息的逻辑,我这个框架就能 magically 跑起来

duangsuse:
所以说动苏的编程风格是函数式改 upvalue 而不是 class 属性,因为我强调算法先于架构

Jack Works:
动苏?啥玩意 = =

rxliuli:
你的中文昵称?

Jack 更喜欢在一个文件中编写多个 func,然后全部命名导出,吾辈更倾向于 class method 的形式

Jack Works:
我这个对 tree shake (webpack) 比较好🤔

duangsuse:
是的, duang 源于成龙洗发液的“头发动啊”,suse 是 Linux 发行,所以叫『动苏』😋 #life

动苏会觉得自称「我」或者「咱」(代替「我们」,我w键坏了) 有点生硬,这样就好很多

duangsuse:
这一点我还是倾向 Jack ,毕竟 Java 算是八股文式 OOP ,没有为实际编程有 toplevel func 样的优化

我可没说错话哦,面向对象的 class 本质是对函数式闭包加类型, property 即 upvalue , method 即子程序化分段,整个对象即 send(name,args) 元方法,真正的面向对象只有「物/例」和其上的名词动词,没有文绉绉的废话甚至混乱 static。 #statement

面向对象把数据和其上操作混合定义是好事,可惜某些人就知道装B 起一大堆半通不通的专有名词,专业术语往往鬼用没得,给人们的思考造成一大堆麻烦。

要是 OOP 最初的作者能有半点实用化的觉悟,绝对不会放任 Jawa 混乱善良合理的编程习性

rxliuli:
但 Java 确实流行起来了而且基本被大规模实用了。。。虽然写起来确实感觉不太舒服,尤其是写过其他更好的语言之后

duangsuse:
所以说它才有机会被 Kotlin 吊打啊~
可惜 JavaEE 是他们自己搞出来自以为高明的八股文,很多 Kotliner 还没做好准备击败他们

CodeHz 📡:
(因为用类作为天然的命名空间分割函数的方法太好了(

duangsuse:
是的,构造器就像可覆写的一个局部变量初始化 header
然后整个类就像一个函数, constructor 提供了初始的变量混入

CodeHz 📡:
(oop 很好)就是无法自然的表达多重dispatch

duangsuse:
polymorphism 多态 不可以吗?

<就有个主次之分了,而且也不是运行时多态

运行时多态上 Sum type 可以 Visitor 啊,也挺方便的

<(有好几个参数需要动态分发的时候写起来还是挺别扭的

c 里搞 tagged union 到处 cast 就不方便吧…… 每个使用处都要检测 tag
请教下什么叫多派发啊

<大概就是这种( https://en.wikipedia.org/wiki/Multiple_dispatch

C#是直接用动态运行时(DLR)了 #dotnet

类似 #Haskell 的 pat match 啊,那样 visitor 的确就不够了,得 trie 数据结构匹配...

非常疯狂,看起来 A.collideWith(B) 和反过来 B,A 是一样的

看起来是个非常有意思的特性,不过我感觉离算法/设计模式比 PLT 近些, visitor 单判定派发更实用一些
#statement #dev #tech #oop 🌝
我已经物理命名法化了…明明之前说要慎用的,笑死

它是以单字符用途不假思索起名变量的方法,如 ab kv 意味配对,xywh 是矩点宽高,ijnm 是2D数组纵横i<n,c配置 e元素 f函数|文件 g图形Ctx
x 也是单项、xs xz 列表和休眠列表next(),ww 意为“w内的w”,w0 意味外层的w或之前的w,1~inf 只是编号,以此类推
o对象 p命题|点|指针 q真假 r结果|弧度 s字串|流 t时点 d翻译表|正负距离|细度 l长度 u链接|blob z休眠中

用途无关平台-View或Widget就该命名为eXX,配置状态只叫c, unord_map就是d或kVs的长名, 无所谓其实现细节,
如果它不兼容标准操作 就用语言让它兼容!如果它有多余功能,无视就好——因为标准操作就那几个
k是广义的键-有v配对就算-i18n resID 都算;如果量有限制(计算量的)意义,可以像i<N这样大写
dt时差 dur时长,cp bg/fg 是单双颜色,ev ex 事件异常,fp路径 im图片 ,
反正能少写就少——但是语义优先,所以它和 ijkplayer 的OI风格命名、匈牙利/魔术风格命名 简繁两个极端是本质不同的

程序是由「统一」和「领域」两部分API组成的,领域名词只有互相联系才有意义,而统一名词没有意义-只有动词能赋予它们意义;越广泛的概念,命名就越该简略-除了是这还能怎样呢? 我们用它的名词是有目的,还是只增加了理解难度呢?
getUnreadBlogs() 就应该写成 blogs.filter{it.unread} 的样子
名字是依附上下文而有意义的,因冗长或太杂脱离了表达目的,程序不过是看起来不可或缺的一堆废纸。再详细的重复名字,在不想看代码的人前都是对牛弹琴-为啥要在代码片段里管中窥豹呢,我一开始就知道要干什么,就自然知道什么变量是必须的,这种篇幅分配 不香吗?
因此我只适当地用介词,重点在前、易改点在后给函数起名,我从不给变量起名——它不值得专有名字;如果写软件,我会先确定有多少「领域」名词,之后代码便不会多加3字以上的变量;把舞台留给函数签名和//注释,这才是最好的文档。
#meme #oop/设计错误
#OOP #FP 可怜人的函数闭包是对象,可怜人用对象表示闭包,都很悲哀 :(
edit: 面向概念和面向动词各有所长,但我更喜欢FP, 语言只提供class会给复用带来很大的问题
duangsuse::Echo
#ce #plt 带步骤的四则计算器。递归逆波兰。22行代码 浅先=`;=;+ -;* / %` 流=(a, _s=[...a].values())=>()=>_s.next().value 切2D=(s,sp0,sp1)=>s.split(sp0).map(s=>s.split(sp1) ) {let t={},k; 切2D(浅先,';',' ').forEach((x,i)=>{for(k of x)t[k]=i}); 符深大=t} 符链=(s,l)=>{let a=[],add=x=>a.push(x)…
#bilibili >那你现场写代码😄
回复 @iiicp :以上是()和算数表达式的求值栈生成,加起来10行。 活动期分析后就可以临时变量到寄存器,或者干脆每个+-用既有栈变量。
当然,C会比JS多费不少代码

但我是认真觉得40分钟太长。如果真的细节到此程度,你可以加提纲,先说说要写啥、涉及啥流程和修改,再放PPT​

你能火是我想不到的,第一期视频我就认为会石沉大海。因为我也会写些涉及文本结构和计算机绘制的东西,在B站这些很少,因此更要注意可重看性。

如果你打算更100天,回头发现这些录屏复习起来很困难,应该就会意识到简洁和代码大纲的必要性了[藏狐]​


@iiicp :Up哥,就是parser这块,看的不是特别懂,可能是,编译原理,语法树,这块,没怎么弄懂​。

1 是常量, a 是变量
a+1 是表达式, (a+1)+1 含括号也是:单项a亦可为(中缀链)
if(a) a+=1; 是语句
表达式都有「值」,语句都能「执行」
表达式也是语句。而在C里,(a=(b=c)) 有效,py里f(x:=1) 有效
它们可以互相引用,像 if(表达式)语句; {语句;},构成嵌套树结构。
最深项先执行,把树变为值称「解释」,
保留中间数据,即区间推断/地址安排称「编译」​
编译的目标是可执行,比如函数,再由「虚拟机」的调用语法填参执行至ret/throw,函数内和脚本顶层是一样的;Java大定义和{},= 内则不同

(为什么要说这么笼统的东西啊喂!😫

常量来自tokenizer分词器,如 "str" 1.0 ,特殊名字如 true 是具名常量;C宏就替换为词条列表
变量可以是 能import的全局表键k、第j号局部、外i层函的第j局部:参数是调用时检查的n或vararg个局部量

(a)=>()=>a 称为词法作用域,a就引用上1层第0号局部-同时是参数。
闭包=匿名类型的值,根据上值(upval)组 "this" 的不同行为不同,它是数据和程序的交汇,Java new-匿名子类。有种Church丘奇编码法: true=\y n. (y) ;false=\y n. (n) ,因为函数是值,能到处传,可以这样。
(值)任何计算的参数,和结果
(弱类型)变量是编译期尚不确定的值,因此+-等需针对2Number有定义..
(强类型)变量值有范围确定。子类型里必是成员集更大的 :T 子类(多态/覆写);可试每位置<TP>归一,类型推导
(副作用) 计算值不能描述的效果。只有数学没副作用,程序只有内存和CPU,限定mut的范围

只有值都到齐才能计算(常量折叠)。其实编译和运行期只是语言执行的实现方式导致的区分,语言本身不限定静态或动态
其实OOP或FP只是数据结构语法导致的区分,算式本身只是参数凑齐,计算更新,单函数不限制功能个数

https://t.me/dsuse/17412
我们都很可怜😔 无论闭包或this都不是廉价的东西,至少不是热销的
#ai#game 魔改就很热销, #algorithm 如前缀树也很热销

Lua和JS,Py里无论有无「独占」名字,函数都是闭包。C等 里函数只是代码指针,也没有局部函数。
一般的Ruby,Java/C#/C++ 则对OOP和FP的等效概念做了较大区分
PHP和Unix族之类我不清楚,它们像操作系统改行来的🌑
#tech #recommend #js
🧐从『函数』的定义就能知道,#编程范式 的发展史
👉 地址symbol、子程序void()、对象 SAM object、算式 x=>y 或文档树、 模式查询select [a b], a=1|a=2

x86无结构:是弱检查指针、面条流控、256项字符集,定长数组,栈分配,加载到内核mmap(rwx..不能为READ 段错误)
是dll内地址

C过程式:是向调用栈赋值后跳过去等返回,是子程序
C#OOP:捕获了局部变量(cellvar,可变)、原型虚表到this,是有Invoke(T)R 运算的对象

Py定义式:是依赖一些数据=>的算式
(HTML,CSS,RPC, py-ast) 是与调用参数对应的嵌套数据 (👍用调用解读内部项目,不关心返回)

TS关系式:是对x+y=2内变量容器 DFS出解集的嵌套(|,=)条件,先深解构到新变量,再构造

第五代:AIGC 不是形式语言,不便于列明框架和接口,但在描述常见需求时,能减少需协调的细节
NodeGraph(Scratch触控) 不是文本,不利于大工程紧凑度,但适合图表,AI

—语言特性是什么
向量:分量同算的2元组,或角度和力度;或按Nd(shape)推广四则的行列向量,👍ML CG DSP 大数据推荐 GraphQL4AI, MATLAB 之源
同构:把 "1" 的加法映射到Int上解决, 把"字节码"视为汇编而编辑,有 cat(X)Y, cut(Y)X 一组转换函数
微分:神经网络是有未知参数的算式(比如用 10=1,11=0 “点集”训练 XOR 函数), 使用"网络隐藏层"向前计算,靠损失(如MSE逼近原输出)做SGD,可以优化出"模型参数"

编译: 缓存流控和(结构)变量 等语法开销的解释期
解析:"abc 123" 吃前缀,吐出 常量,[],情况?, [1*2+3, 4]: [[ 'tuple' 1 2 * 3 + 4]] 树,方便多次深先遍历的 cat(同构)
分词:因为解析器不懂记录区间高亮、只重读最近一级'{}[]"" ',😇 想靠二次遍历 提供高亮、优化editor的性能
编码:C++ 可使用UTF16 L"你好" 迭代(解码)字符,输出时需压缩到UTF8。Windows 的坑多 exe可能是非Unicode.. TCP黏包:收发bytes时忘记填消息长度!

类型推导:让调用树构造出类型,可以含函数级未知变量: P<KV>就真的是编译期到处传的Pair存储。P<get T> 可为P<T1> ,Fn<set> 反之
模式匹配出调用(List,Fn)的成员交集,List<R> 就在匹配里统一,查找重载。


异常:可能为Err的返回值。需级联返回 伪递归:改参重来
事件驱动: 主循环if一些(用户输入,异步赋值) 变量的改变,触发相应的更新重绘函数。像CPU信号
Rx:函数间提供流(Channel)通信,来分配并发, 而不是 Promise.all 或Worker池的模式

调用链: T.f()={runJob; this as T}, 即 T.prototype["f"]=(*arg)=>(f.call(this,*arg) ,this.copy(K=V?) )
T自身的proto=基类, 直到Object不用再查"虚表". T限(ctor)函数, v8创查{}更快, 但可以用Map(需 get key()=equalsAsStr)

#FP 纯函数: 数据皆静止,调用皆惰性. if let 解构=值构造器可以含可变<T>
反射:即让(参数)类型 实现 Type 接口。在弱类型里元编程才算直观,可实现 toJSON, 0参创建,依赖注入(=按类型.ini) 等样板

协程:调用方自动传回调(即yield job 后的流.next)
因此,其“返回” 变为由(不卡调用栈的)子级们催促,终于(在某个调度器)计算
即函数级线程,回调,Promise 即 函续Continuation


需要注意的是, 向量矩阵是快70年前 Fortran 里就有的概念,协程30年前Lua就支持,Lisp 链表函数也是60年前的老体系

技术没有变好,只是用户的审美越来越刁了! 😇反观一些学院派, 竟然和”脚本小子“ 一样,每天把文档写成代码、 代码写成汇编 ……

程序员和卷王常以为,拥有知识,是天才的骄傲的事,是智商的”碾压“,行数越多人越值钱。 🧐但回看历史,一整代人都”会数学“,却只有numpy让物理公式,真正造福于生活。

人类走向现代文明,不是靠吃”聪明片“,而是”教学半“的合作与积累 ;获取信息是一项人权。没有开明的思想,技术不可能改进与繁荣。
能够触摸开源社区研究的繁荣,却害怕”核心技能“被人偷走,是无法融入正常社会价值观的体现
#PLT #OOP #design

☺️ 绝句的OOP部分完结了。 包含type,name,named 「典-构造器 interface」「名-class」「曾名-加构器」3种概念

type 类似Rust的 enum Either{A(A),B(B)} ,但可以外部扩展

type Zoo impl??
Zebra(:Name,:Age) //<>列方向是cols
Elephant(:Height) //^v行方向是Conds

type Zoo
power Int
Tiger(); Lion() //和enum WithData()一样,生成构造器

type Inc Int{>0} //类型只是N个字典+几个新词的组合
type 'T'Pairs [T T Col2] //所以,没有啥typealias

named 类似inner class,但可以外部扩展 Point(0,0).Arc(10)

type Any
Point'xy'(_:Int)

named Point.Arc(r:Int) //加构器
- draw 画圆

好吧,写错了,Any的Point构造器,理论上无法继承:type数据间不可以组合

但name呢? 传统的 abstract class有啥用?? 我很想扔掉它们,我在SO上搜了很多,但没人说服我为何「组合优于继承」(甚至这句话居然是OOP专家说的

type Geo
- draw

name Point'xy'(_:Int) Geo
^type
- flip Point
^type impl
- draw 画1px圆

这个语法是为OOP兼容保留(override fun 啥的太扯了),好像比接口多提供个构造器、protected复用(被Utils取代了)、final等「更准的函定性」

但它对语意真的没有啥贡献? 只是像Scala那样,简单把同名的 struct+trait 连起来,而且逼你单继承??

我是更看好Rust的impl式多态,包括py的Protcol,虽然很复杂 {}构造器也很乱,但类型的限界都很清楚,不像今日JVM C# 这些接口子类分不清的

---

其实我清楚,class比接口允许「更准的构造顺序..函定性」,它根本就是--js的传函数字典 ,或者说类=可改传的多项函数 接口=dyn字典

如果你写过愚蠢的 android.view.Listener ,会发现它们乐此不疲地把本该叫lambda()-> 的变量搞成override,所谓的设计模式。。。

^type 就是默认参数的另一种写法而已,而 ^type impl? 可以选择不封闭既有值

绝句主张函数与Fn值的统一,但考虑 - f'xy' 和 F.[Int Int a2] 本不一致,无法在语法上实现静态-动态类型的交融

期望未来能找到更彻底的「解决语法」(想到一个,除了构造器、加构器, 还有 type mv(src, dstFile) 这种「默认参器」
只要我换成 name mv(src, dstFile) ,是否就把函数和class联系起来了? 😋


btw. 绝句的结构写起来真是太爽了,可惜表现力比不上纯数据的JS。 希望在词级 算式级 也有更新的发现

btw. 我打算把语言改叫《海经》了,因为这个时代,已经不适合在单句和算式级别,纠结代码怎么写了。 手写的代码都在词乃至类型级别, 而且绝句一开始是为逗句缩进起名, 但如今它的对象和集合模型比缩进有趣一些
duangsuse: #kt #book 元编程
http://www.bilibili.com/video/BV1XH4y1w7mT
https://drive.bennyhuo.com/zh-CN/talks/2018.11.17-%E4%BC%98%E9%9B%85%E5%9C%B0%E4%BD%BF%E7%94%A8%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B_final.pdf

https://weread.qq.com/web/reader/f7632a00813ab82d6g017b14ke4d32d5015e4da3b7fbb1fa
可以一起读
虽然我不觉得这点值65😊

如果numpy那种API/DSL都设计不出来
修改class的结构也只是给开发者们徒增烦恼罢了

举个例子,此章节的 gh/user/_name
如果只是把它当成URL路径,需要绑定,显然造成代码重复,与元编程的本意违背

而如果像 import fire 那样,知道URL的本质是class路径与def GET,POST等,也就是另一种CLI调用
就不需要写什么注解和函数名
甚至模块化都省了,一个文件足矣

不过是修理servlet.xml繁琐和不支持argbind和的“弱类型”问题
但何必要制造那么多问题呢?sql,http,那么简单的工具还用学

#parser #learn
说起来,AST也就是多方法的 ()->Any 而已
你甚至可以把方法名enum化,从而完全避免使用class
例如 sum(L(1), L(2)) ()==3 只需要两个fun
Object Algebra.. 嘛,用虚表override取代if,稍微快点,只是要parse两次

至于在js里,我一般用 [[JSON ',' +] '()' /] 这样的模式写ast
描述 (1, 2, 3) 这种正则
甚至连函数式都没用到。 数据结构本身就蕴含了for if流控,运算符重载本身就是编程语言

不需要任何范式来实现他们,“数据结构与程序语意直观对应”,这就是CS。
这……应该是一件很难听懂的东西吗? 为什么DSL都设计得那么刻意和拉垮?

甚至,构造函数也应该取代class{} 或tuple才对,为什么把参数传递到堆而不是栈里,就需要写所谓的struct? 它们都是把args打包复用而已
为什么把yield 外提为语句,变成
let then=回调=()=>switch{} 里的编号,就需要学什么func*和async,堆和栈,难道不是天生一体的么? 分页数组、“缓冲区”,难道不应该是跨语言的?

然而支持kwarg的python 却需要Namespace来实现这种等量代换😒 反而是Haskell可以这么写
然而它是真正的笨蛋美女😅

#oop
元编程,首先就要明白obj的本质是通过enum分派逻辑的(vararg Any)->Any ,也就是一个when(x)in constMap+super..
这样才方便添加和绑定方法签名

这样在语法上也就能理解为什么是{}包裹,以及filter{}为什么优于lambda和匿名override

py可以通过vars(o)实现静转动态
typing.Namespace(kw)反向
除了小写类型不能扩充,哪怕是Ruby元编程在直观上也无法和它相比了

duangsuse:
oop和rust go就是pp的扩充
不算重新学习过过程试

编程语言只不过就一张加减乘除节点图,问题是领域和API

看这本书的“层次结构”,就想到拿identifier叫name,拿classifier叫tag,拿些辞藻和皮毛当本质,哎
无聊
好像早点拿到电脑,多写代码
Forwarded from duangsuse
🌚 刚才想了想,确实无关于ktx的Encoder APIs #oop #statement

我只是有点感叹,学那么久JVM/C# 的“安全的”托管代码,业界最终还是没解决var binding的问题。

有大牛说,计算机科学里最大的两个problem是命名和缓存失效(React里的memo, poll轮询和Svelte里的push就是典型的缓存刷新范式),深以为然

实际上,C的 堆/栈/指针 范式的问题,也从未被OOP消灭过,就连data class也只局限于语法糖,而没有俯视“数据类型”这个整体

fun2class即 栈-堆 的绑定(协程、CLI、RPC解析的最优解)? 不存在
class2KV即 堆-RPC形式如txt(0拷贝和序列化的基石) ?要配环境

许多人痛斥C的 int* 和Rc对象树,却对JS的 new Signal.State(0) 疯狂打星
所有人并不知道,如果把 heap/ref 值真正统一建模,gradle minify, js tree-shrink 只是对文档树进行GC

C里用mmap设置下list[len],obj.type 就能“读写”的数据, 因为只顾自己的一亩三分地,许多人根本认识不到: Reader/Writer 的本质只是把流的i32,i64 从栈复制到堆上,再回到栈上,即 this.x=read(); ..

其实,“程序结构与数据结构直观对应”有多重要?
从你编译程序开始,到任何数据..或代码被跨端复制- 甚至仅从JS复制到XML/html,都存在这类的样板代码。
然后,便有一堆良莠不齐的框架跳出来帮你“提高写码效率”,顺带兜售自己造成的一大堆问题和“知识点”。

他们甚至不知道,堆/栈/指针值、单线CPU多异步任务,这就是50年前困扰C的问题。

但能杀灭这些问题的算法呢?“解释器”的降级版,DSL,能设计好的人都很少
编译器学生,例如ANTLR的吧,沉迷于用状态机重造x86调用栈的轮子
函数式er 并不重视程序的语意、实际应用需求,只是痴迷于链表、深拷贝、abstract nonsense,和从Prolog偷来的模式匹配。

发展了70年,除却类型冗余不统一,就连IO都做不好。
man, what can I say?😔
duangsuse::Echo
>火之魔女: 不过unification我是想写好久了(应该按年计)但是一直没写的( https://github.com/duangsuse/mkey 写过,不过落后很久了 #sql 这算法就是 unify(a,b); unify(a,1); unify(1,a) 得出 a.v==1==b.v reify([a]) 解引用一下=[1] ,其实也挺有趣,包括npm也在牵强附会这玩意,真让人搞不懂从哪看的 http://minikanren.org/ 使用了一个自有的def: yield 实现,对 a&b…
#OOP #plt 学点设计模式
https://iota.huohuo.moe/OO-in-C.html#:~:text=一种设计模式对应一种语言特性%20%20By%20千里冰封

函数式人有许多「过度设计」,例如美 kotlin.Any.let 其名曰 #FP Functor.fmap (Arrow-KT.io)。这种(私货+算法)的泛滥,给IT带来了灾难,让许多初学者不明觉厉,也当然不能提升其应用能力(毕竟只是"指针别名"嘛)
https://kotlinlang.org/docs/scope-functions.html
https://www.ruanyifeng.com/blog/2017/02/fp-tutorial.html

但OOP也有自己的“私货”——用于弥补语法不足的“优雅的”设计模式
例如 Builder,Utils,Adapter,Delegate.. 它们是对this参数、对interface扩展不够灵活的变通

这个长文,我会用短 #kt demo 让大家看到 refactoring.guru 🐿收录的10种流行 Design Pattern 掩盖了哪些语言特性的缺失
以及科普"OVDEP" Observer Visitor(深先iterator) decorator(单参compose) EitherAB Proxy 等不逊色于箭头函数的,超越语言的优秀工具

## 创建性-Creational

这些模式是 new 构造器() 的变体,在Rust里被 fn new=Pair{A:1, B:2} 构造字面和 impl T for T1{} //mixin T1: T 混入取代

1. StructBuilder

有一个很长的SQL row需要new,可以使用默认值,插入前也有检查

class RwCol2<A,B> {
var A:A?; var B:B?
constructor(x:A,y:B){A=x;B=y}
constructor(){A=null;B=null} //默认值
}


我们把构造器中A=x;B=y; 拆成 newThis.A(x).B(y) 两个函数,就能实现初始值的解偶
填完数据可能要验证,如编译期验证不可变 fun build()=this as Col2

与它对立的是默认参数
RwCol2(0,0).apply {B=B+1}.B; buildList{} this参数上扩展 apply(T.()->*): T
K2 value class{init{}} 也实现了构造后验证,不过大部分人仍在使用专门的反序列化和data verify框架

2. (Abstract)Factory

常见误区是,Factory类似 Pair.of(1,2) 是为了重命名掉new,或者只把构造器集结起来: doc.createElement("div")
安卓 content.Context 与Button等View(ctx)的关系更像工厂的本意: 基于(操作系统)上文验证和保留数据

interface DataJVM {
fun <A,B>List(a:A,b:B): Pair<A,B>
fun <T>List(vararg x:T): List<T>
}
val kt=object: DataJVM {
override fun <A,B>List(a:A,b:B)=Pair(a,b)
override fun <T>List(vararg x:T)=mutableListOf(*x)
}
//val py=object:DataJVM{}


与它对立的是全局对象、元类trait。
全局fun弥补constructor钉死了 open fun 且难于校验的问题。当然!它也消灭了 object Singleton{} 和“双检锁”的样板
元类允许了 static (类名上)接口,而不是让可覆盖的函数代理一下构造器:
https://docs.oracle.com/javase/8/docs/api/javax/script/ScriptEngineFactory.html

3. Prototype

Linux对pwd等环境变量的fork()是最著名的原型模式,这使得父子进程间有了T1继承T 的关系
JS里 {} 等价于 {__proto__: Object.prototype} 函数表,函数表也可以随时添加继承。有 new.target 的构造函数()只是设置原型+赋值到this的简写
一切皆对象,除了 Object(1).valueOf() 里装了又拆箱的1。无原型的,只有更慢的 Obj.create(null)

data class 会自动实现 fun copy(),但它不能继承,因为无法拷贝父类的变量。Java里很难把对象加构成更大的子类(除了 inner class)
sealed class Box<T>(val A:T) {
inner class Pair(val B:T): Box<T>(A)
}
val x=Box(1).Pair(2)


按道理是x.A=1,那么Box(1)单例就是这些Pair的原型