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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
学到了学到了,不过这样的代码我是不会再以非重构目的阅读了就是。
乍一看非常厉害,其实也没啥算法,而且都是在无用的地方下篇幅,死板的机器 formatting 我也会写那种 reformater 呢,何必呢。

从根本上设计就有问题,过于复杂,看起来再难以理解也只是给自己添麻烦而已,能做出什么呢? 支持的太多,最后反而一个也用不到,自己也弃坑了,简直是暴殄天物。 Kotlin 这样融合OOP和函数式优点的语言拿来写这种烂代码、虚浮的内部建模,没有多大意义
混乱的代码就不多发了…… 这个拿来充当反面教材都太重口了。 隔壁的 CliKT 代码质量比它高到不知哪里去了,我从那抄 multiplatform 的无趣味代码抄得谈笑风生,而且都不需要重构。
duangsuse::Echo
混乱的代码就不多发了…… 这个拿来充当反面教材都太重口了。 隔壁的 CliKT 代码质量比它高到不知哪里去了,我从那抄 multiplatform 的无趣味代码抄得谈笑风生,而且都不需要重构。
仔细解读下这个反面教材哈, #Kotlin
1. optionFullFormPrefix 太长了(别告诉我没法短,不能短也得想办法变成 Pair 之类的弄短!)
2. 顺序虽然是统一的出现/依赖顺序而非重要性顺序,但和 prefix, delimiter, deprecatedWarning 放一起实在太草了,何况也并非严格按建模对象的出现顺序, full/short prefix 其实是并列的。
3. textDescription: String get() = 没有问题,但是后面还有一个 formatHelp: String get() {} 就实在是太糟心了
4. TResult ? 难道你不用 R 吗? 而且 T: Any 的 constraint 真的有意义吗? 很多时候在有 null T? 成员时根本不必显式指出的
5. 排版问题。 T? 和 T ?
6. ArgType<T> 和 TResult 的关系存疑,理论上只应有一个。 要知道 ArgType 是包含 convert 方法的。
7. Nullable 的东西太多了,设计建模可能有误会没消除
🤔 #zhihu 上看了 #Cplusplus 的一个 stream lcm 最小公倍数:
#include <iterator>
#include <numeric>
int main() {
int[] xs = {2,3,4,5,6};
cout << reduce(begin(xs), end(xs), 1, lcm<int,int>);
cout << endl; //^ 60
return 0;
}
https://coolshell.cn/articles/21003.html #web #security 草,原来字符串比较算法的耗时也可以被用来猜密码, str.zip(str1).fold(true) { (a, b) -> a xor b == 0 } 而不是 str.zip(str1).firstOrNull { (a,b) -> a!=b }
我艹受不鸟了,这是啥玩意啊『前端』……
#Cplusplus 这个 template 技巧收下了!
C/C++ 函数返回值可以不确定吗? - IceBear的回答 - 知乎
https://www.zhihu.com/question/414206269/answer/1408101568

template<> int f<int>() { return 1; }
template<> bool f<bool>() { return true; }
or:

variant<int, bool> produce(string &type) {
return true; //有时需先声明作局部变量 不然类型错误
}

auto visitor = [](auto &&arg) {
using T = decay_t<decltype(arg)>;
(is_same_v<T, int>)? f_int()
:(is_same_v<T, bool>)? f_bool()
:nullptr;
}
std::visit(visitor, value);
🤔 老实说我现在最看得起的「设计模式」只有 Delegate, Observer, Visitor, Kotlin 的 scope function let/run/apply/also 和 null/elvis chain 以及 OOP 原生的 嵌套式构造器调用、字段初始化、方法解析 。
This media is not supported in your browser
VIEW IN TELEGRAM
玩得再花,不能解决实际问题也是废物。还不如实在点、自然点,在合适的层次解决真正的问题。
所以说设计模式什么的都滚蛋吧…… 只有数据模型和程序的共鸣最重要

最近我设计的 ArgParser 和 ParserKt 也都只用了 Delegate/Visitor ,没有其它古古怪怪的 Adapter,Provider,Builder,Factory,Command 这样的东西,无脑的复制 pattern 显然是不好的,乱用各种 -er 对象更是不可取的操作……

所以说把函数式拿来修复面向对象的设计模式里各种奇奇怪怪的名词是最好的选择,而且也解决了函数式不明确、太隐晦的问题。
动态规划和递归算法有什么不同呢? #Algorithm #zhihu

动态规划是递归的子集,它解决的问题包含子问题有重复的情况。

比如说 factorial: 1 -> 1 ; n = (factorial n-1)*n , f(9) 和 f(10) 最终都会调用到 f(2) ,如果不缓存的话开销比较大,而且不能把俩子问题放一起平行比较。
在算 fib(n) = 1 -> 1 ; 2 -> 2 ; n -> fib(n-1)+fib(n-2) 的时候就更明显了,递推调用栈会变成长长的一串,所以递归也不是万能的,主要是用来写 DFS(深度优先搜索)
……有时候感觉 C++ 的设计还蛮一致的:
+ auto 在 C 里是和 register 一类的 storage classifier ,默认是栈上分配, 而 C++ 只是添加了自动类型的特性
+ template<> void op<>()lambda 的 []() 参数顺序有异曲同工的感觉, 都是上下文性质的形参放前面、参数放后面
duangsuse::Echo
🤔 老实说我现在最看得起的「设计模式」只有 Delegate, Observer, Visitor, Kotlin 的 scope function let/run/apply/also 和 null/elvis chain 以及 OOP 原生的 嵌套式构造器调用、字段初始化、方法解析 。
刚才没把 Observer 加进去,其实 ParserKt 的两个版本里都用了类似 Observer 的东西 —— Reducer<T, R> ,类似 java stream 的 collector ,它可以分配一个新对象,在流上运行 onAccept 方法并 finish() 出结果。
Observer 就比我私自造的 Reducer 多一个可选的 onError 方法,所以它是一个完整的设计模式,和 Promise 一样同时定义基于 Exception 的异常处理。 (术语当然是有区别的, Observer 的是 onNext, onDone, onError ; 我用 accept 是为了和 Consumer 的动词保持一致以及强调语义)

onAccept 是被动侧,处于调用栈的上方,无法捕获调用侧的异常,所以就把捕获逻辑做到栈下方的主动侧,再把异常传到 onError 那里
哇原来我之前在 #Haskell 里看到的就是这种…… 这个大佬很厉害
https://teek.readthedocs.io/en/latest/_modules/teek/_tcl_calls.html#init_threads
def _pairs(sequence):
assert len(sequence) % 2 == 0, "cannot divide %r into pairs" % (sequence,)
return zip(sequence[0::2], sequence[1::2])

#Python
_pairs xs = zipWith (\a b -> (a, b) ) xs (drop 1 xs)

*注:Haskell里\a b = lambda a,b: ,而且它的xs::(List a)是纯流式的
Python的slice with step xs[start:stop:step] 这样写了,默认可以省略的 ( [0:len(self):1] )
真是服了 #Python 了…… 开始见到越来越多不常见的语法能用的了

才知道为什么能有 @property 这种东西,原来 obj.x 其实是 type(obj).x(obj) 的意思,而 Python 的 obj.op() 其实是 Kotlin 里 (obj::op)() 的意思,默认bound,草

之前不知道 nonlocal 与 global 有啥区别,然后觉得 assert condition message 应该用 :而不是, 切分
上面的 [] slice 省略 end 后一个 [a::step] 瞬间感觉让人高大上,其实这应该还真能做成DSL语法,因为 Python 是动态类型…… 混乱
今天又有 Exception.with_tracebackraise exc from None
而且 functools.wraps(op) 加起来到底有没有意义呢…… emmm
不过在看过 pygame, tkinter, teek 里的 message loop 后我也终于理解 Android 里 os.Looper 和 Handler::post 的语义了…… 这么说 Handler 应该也有一个 pre(before) 方法, post 是 after 嘛 😂
pygame 和 tkinter 里的设计都蛮像的,不过前者不提供 .mainloop() 而是用 pygame.events.get_events() 要手动 while True: ,不过 tkinter 里用 tk.after(msec, handler) 注册 event queue poller 也是差不多,如果看 Elm-lang.org 的"四大项目" state/view/message/update ,就会发现它也隐含了一个 message queue

(话说 Python 里的 queue.poll 会用抛出 queue.Empty 表示结尾,我觉得这种方法更好,也是我少数赞同的几个 "Pythonic"... 应该说要能取其精华)

而且也明白为什么之前有时候不在 Main thread 更改控件树也没抛异常,而onClick阻塞会卡死主线程,就像 ConcurrentModificationException 一样,不一定是每次都会抛出的,有时候只是运气不好碰巧没有挂掉而已。薛定谔程序。

其实就 #GUI 而言,我更喜欢 DOM 风格或 GTK# .NET 风格一些(C# 的 event 可以用 operator overloading += (ev) => {} 也很好看啊),不那么偏向设计模式所以视图组件树显得很简洁,只需要在 <div> 里 appendChild 或者用 map 函数,也没有 ListView 要加 adapter 来建单项视图什么的,不需要 Model/View 也不必用它的 item delegate 去创建 editor ,简单来说就是因为功能受限,只能开发些常见的小工具啦…… 可是我还是更喜欢 DOM 风格一些

恰巧这次我要弄的一个小 GUI 只是个小工具…… 我很奇怪为什么要为弄一个小工具废很大的精力去手建视图树,不过在 TkGUI 里我只用了 pack 布局管理器(算法) 没支持 grid 和 posit
Tk 其实不是很好看,不过我的编程概念就是定义式——只写它是什么,不写怎么实现 ,所以代码基本上都会分为抽象层和 stub 层 桥桩层,所以 TkGUI 要是能再走一步,我会让它采用类似 Qt 的 Font/Pen/Palette 风格抽象,当然一切都是抽象的,所以我猜它可以移植到 wxPython, JPython(awt/swing), PyGTK, PyQT 什么的,不止是 tkinter。

Qt5其实也有这个东西…… 就是 Qt 的 QML Quick prototype (对别人来说是原型,对我可能就是成品了,当然我开坑的频率更高),不过那个东西的功能更少使用更复杂…… 但不得不承认无论是作为跨平台框架还是 GUI , Qt 都是最成功的一个。

想着啥时候可以再去了解下 SQL, ORM, Vert.x 的 HTTP 什么的…… 不就是所谓的全栈了么2333


马上要给 TkGUI 加的特性是我从 Teek 移植过来的支持在多线程更新控件树。 Python 标准库的 tkinter 的 bind 实现不是线程安全的, Teek 很厉害,在它的 _TclInterpreter.init_threads 后会注册好一个 1000ms/20times (=50ms) 的 event loop after-callback 来处理一大堆诸如 call, getstring, eval 的线程安全调用(很像 Qt::connect 里的 Auto/Serial/Queue 参数,不过这个是全局的,整个 Tk 都线程安全,可从任意线程更新控件)

不过我不打算按照它的方法加这个特性,因为我目前只有做 tkinter wrapper 的精力,我不想动它的隐藏 API ,而且这个要替换 TclInterpreter 实现的重构要从AOP(面向侧面编程)角度修改所有 tkinter.Widget 的行为…… 有时候是构造器参数,但往往是私有属性和私有类,或者全局变量什么的,实在不想研究它的代码。

Qt 的 connect mode 起发了我,其实可以给发起异步动作的 button 什么的单独弄个 asyncBind …… 不必在全局支持 threading ,只需要 bind callback 是在主线程顺序执行就可以了
https://mivik.gitee.io/2020/08/29/kamet-basic-implementation/ #Rust #Kotlin #PLT #CS #ce 草,太大佬了这个
最后还是支持了 traits ,是 Rust 式的 fat pointer 实现,当然也有 struct 和 new 了
(特殊类型 &dyn [TraitName] 会存储两个指针,一个指向实现该 Trait 的相应的函数表,另一个存储指向该对象的指针)(当然这需要 constant method ordering)
(而C++式的 virtual table 实现是添加虚表指针成员,那样开销更大,当然 vtable/fatptr 的选择也是看创建对象多还是指针引用多啦,显然是创建对象更多)

目前支持 extern,no_mangle,packed,inline 四个 attribute, inline可以是always或never(符合LLVM IR里的版本)