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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#c #php #java #recommended http://ice1000.org/2018/09/24/CodeEditor4/

duangsuse 阅读时注意到的事情(本文第一次,作为编辑器后端架构基本蒙蔽)

0. 我又看到了 gap buffer
1. freenode #lisp 有 dalao
2. Oracle 开发 JavaX 的程序员很有文化
3. VSCode 前端程序员们有不考虑字面 literal 包含 EOL 的 Token “优化” 的黑历史
4. 他们曾经也没考虑当前编辑行
5. VS 很厉害,会缓存每行代码渲染后生成的纹理 buffer
我也想试用下 FreeType 来着
可惜后来没时间了 2333
我曾经修改的一个 Rust badge 生成器,现在还在 docs.rs 上,用了 FreeType 的一个 Rust 绑定,当初看不懂 算
6. 冰冰现在也做数据结构 & 算法可视化动画了 LineSpan 的数据结构可视化
7. 太长不看 TLDR
8. 所谓太长不看的大多是 文本序列数据结构的通用性质
讲的还挺好的
+ 一个 item 指文本序列的最小单位,通常是 char 或者 wchar_t
+ 一个 sequence 指一系列以各种方式组合并在逻辑上是连续的 item ,即刚才提到的抽象结构,比如 LinkedList<Character>, std::list<char>
+ 一个 buffer 指一段在物理上连续的 item std::vector<char>::data, java.util.ArrayList<Character>, mmap() 映射的
+ 一个 item 序列如果同时是 sequence 和 buffer 那么它是一个 span like java.lang.String, std::string
+ Ruby/Lua/JavaScript/Dart/Perl 等语言中的 string 是 span
8.5. PHP 也是,如上文,Java 当然也是

// 可以认为 PHP 里 string 是这样的
struct php_string {
php_refcount rc;
unsigned long hash;
size_t length;
char buffer[1]; // 多出来的一字符用于存储 CString 的 EOS '\00'
};

这里 struct php_string 是一个 item 为 char 的 (sequence 兼 buffer)a.k.a. span,因为它在物理上也是连续的

9. 菜鸡 duangsuse 也是正式入坑 CS 足足一年半后才知道啥是位长度啥是进制的,烫烫烫烫烫烫烫烫烫烫...
10. code 现在使用 Piece Table 来作为存储后端数据结构实现
11. 简单数据库操作 CRUD 简单序列操作 QID
WebPack Gradle http://ice1000.org/gist/posgen-gradle/
知乎 Haskell 蜘蛛 http://ice1000.org/gist/rina-spider-zhihu-stu/
C++ Vector http://ice1000.org/gist/vector/
Agda 类型安全 printf http://ice1000.org/gist/safe-printf-agda/

#recommended #backend #blog #lisp(希望大量转载不会引发版权问题 😶
Forwarded from 看看就好的频道
From Macros to DSLs: The Evolution of Racket
https://www2.ccs.neu.edu/racket/pubs/snapl19-cffk.pdf

一篇回顾性质讲 Racket macro 发展历程的 paper。

从最初的 LISP 宏讲起,到声明式的 define-syntax-rule,到 Chez 的 syntax-object 和过程式的 syntax-case;然后是 Racket(当时还叫 PLT Scheme)关于 macro 的尝试,包括曾经试图把 macro 和 first-class module 配合的努力。再到现如今的分 phase 的 first-order module,以及 Racket 一大武器 syntax/parse;最后还说了一下基于 syntax/parse 的 typed meta-DSL, turnstile。

即使对于 Racket / Scheme macro 不感兴趣的,也可以从前几章了解到 LISP 系宏的发展历史;还可以通过最后部分了解一下 Racket 的 "macrology"。

#racket #scheme #lisp #macro
duangsuse::Echo
唉,这位的文风也很清晰,而且他居然会为附加功能的缺失说 Sorry ! 看着看着就莫名觉得很感慨😳, ParserKt 所谓之「不制造问题」是有多深刻啊…… 几乎所有的,哪怕函数式解析器框架都支持 Backtracing, ParserKt 刻意只让 peek(1) ,即便现在也醒目地和新 peek(n) 划清界地(这也是 "Decide" 这个名称的由来,因为它只能判1字符😂),却可以让用户清晰地利用 Piped.concat 解决 Name|Name '('{Expr}[',']')' 的歧义消除(而不是先读个…
https://epsil.github.io/gll/#continuation-passing-style-section

#FP #scheme #parser 想了解 continuation-passing-style (没有 return 如何编程?)的大佬们可以看看这人的文章,我觉得相当好。实用性,王垠那几十行代码不就是 CPS 优化吗。

照例个人观点:
0. 上文定义了 success/failure 的 union ,以及 (successed val rest) failure ,还有添加回调的 (bind p f),基本是 (match (p s) [(success v rest) (+ v 1)] [failure failure]) 这么用的。
实现的解析器不支持流,支持 substring 。传递方式是 backtrace (比如 (string "abc") 在 (seq) 里成功则 (cons "abc" (cont "")) 失败就只是 failure 单值,所以要利用 memo 函数)

1. PKT 是不需要这种“优化”的(顶多比过程式慢 50倍的纯函数式框架要用),因为我们的 Seq 明白一解析器失败不考虑后面就 return notParsed ,不需要玩 p1(p2(p3 { })) 这种耗栈的游戏。Kotlin 不支持 CPS 优化,编程也不是智商测试。

2. CPS 也是有一定价值的,虽然它会损失一定性能,但能够拿到调用者的句柄(比如在有 Decide 的模式里,就可以后继操作遍历所有分支了,或者进行异步回调"thunk"函数)。和非 CPS 一样可作为 suspend fun 协程

3. 即便这篇文章相对易懂 #Lisp #Racket ,我不建议大家认真用 Racket ,原因是括号的表现力不够

比如文中 (let (result (apply op args)) (entry (mcons args result)) (set! alist (mcons entry alist)) (m=map)一大堆括号,有没有注意到 (let (a v) expr) 只是为可读性而加的,量定义可以内联…… 只是表达 alist = args to op(args) : alist 甚至 alist[args] = result 的意思呢(这例还是SICP里的呢,多余命名量本身就可能意味着语言性能缺失😢,比如『文言文』里甲乙丙丁一大堆OK么)…… 函数式那么多年修成正果了,开始从“无副作用”往“看起来像过程式”靠,草生(* ̄m ̄)

4. 从解决实际问题而言我觉得 ParserKt 更贴近,但这个文章所创建的解析组合子用更少的代码定义了更广义的实现方法,非常有意思(最后也用左递归和 regex 创建了计算器,缓存和穷举最长匹配问题如此有意思以至于我开始可惜PKT不用处理它了😳),而且也易懂的讲解了 CPS/trampoline 以及“穷举所有可能结果”的正统函数式思路 #Learn
#lisp . #scheme #plt #parsing 🤔👍
看来我以前还是想多了,简单的方法也可以带来巨大的变化(指用缩进)
define fib(n)
if {n < 1}
n
(+ (fib {n - 1}) (fib {n - 2})
duangsuse::Echo
#plt 呃,这几天眼睛有点疼,那个网页重构也接近尾声了(目的就是交个PR),马上把雄狮扭眼的”热度蹭完“,我就能开始二进制pybind了 ……但是到2月我就必须开始制作一个H5动画礼物,以现在这个效率…… (而且之前说的 Java 入门又鸽子了,尽管对话框和离线javac的问题解决,其他内容还是需费精力 说真的我没一次蹭上国内热度,因为每次都是我趁机学了些”没用的“(比如彩字符画、粒子动画、MBR程序、C指针和数组啦),然后数据不好看 😂 这次也是一样,我用shift重映射圆心距l=1~len 环上像…
我太阳,才发现这个别人能发博文的东西,我竟然连标题和名字都没起,试运行成功贴上就pass了…… 这不是在线教SICP(程序的构造和解释)吗🤪 #lisp #fp #zhihu #statement
放到以前我绝对搞大新闻一样,就像之前仿造(但也没成功)Lice 时专门建了项目画了logo,然后文档拼缀别人的,最后模板代码写完不会了 🙈

但说起来,元编程最后也不过是编程。你了解编程语言,很好,但语言只是载体,美丽的、各种各样的应用才是我们的最终目的。
你能写编译器,很好,但也不过是完成了文本模式和树遍历,加上一些理论。 编译器的中/后端分析优化 也是同样的处理流程,也有简单和最优的做法,「编译器」,对这个流程而言并不特殊。「编程」,对代码可变的计算机并不特殊。

就像让语言运行(尽管一些没执行序)于计算机的工具,也竟只不过是种应用,如果你了解可复用的前缀解析器:
#js #code #parsing
feed=(s,i=0)=>d/*+peek -take*/=>{let q=d<0,r;if(q)d=-d;r=s.slice(i,i+d);if(q)i+=d; return r}
feed=(s,i=0)=>d=>d<0?(d=-d,s.slice(i,i+d,i+=d) ): s.slice(i,i+d) //返回前可加过滤空格(当前tok==0? 跳空格)和'\n'数行号
sign=s=>{let k=s(1),i; if(-1!= (i="+-正负".indexOf(k)) )return i%2==1}
num=s=>{let n=0,di;for(;/\d/.test(di=s(1));)n=n*10+(s(-1)-'0'); return n} //可以用-0 确保for至少有1次.
Seq=(...ps)=>s=>{let a=[],p;for(p of ps){r=p(s);if(!r)break;a.push(r)} return a}
pSelf=pOf=>{let p=s=>p(s); p.give=(P=pOf(p))=>p=P; return p}//wait give

"+123 负3 正2 -1".split(' ').map(code=>
Seq(sign,num)(feed(code)) )
呃,测试就不做了,大家作为小练习吧(反正外面也没讲的,不信你搜(
顺便一提: eCall 的首项其实不是 d[kf] ,能继续(yes?fa:fb)(1),这也是个易混点。 let x=1 in e 与 ((\x. e) 1) 不完全一样,前者不涉及”函数作值“

那么语言的实现,以及各种DSL(make,ant.xml) 与普通CLI程序(grep,sed,..)没啥不同。 得到了菜刀,就更要懂得取舍其能力。 菜刀不能用来干什么? 如果这么用,人多后风险是什么? 怎么最简及最优地添加功能? 这才是编程语言爱好者该思考的问题。 编程语言是更精确的自然语言,优化一篇文章和优化一段代码,是存在不少相似性的;编程和数学都能”提升思维“,但编程更擅长表达。表达也是智力。

解释或编译,JIT为REPL执行或动态优化,都是相同目标的不同选择,大同小异,关键在懂得它和已知知识的差异。
(补充: Fun,Call,var 在函数式一般称 abs,app,subst .当然王某那篇 就没有用这些稀奇名字. 我这里没有let-in 和 (+ 的 prim 操作,都是通过JS 函数相互引入。换Java用reflect也可

Java/Kt实现之所以长,是因为要强类型检查 而且fun eval() 和override啥的重复许多遍,语义上并没有新概念
C/Py实现之所以长,是在文法期(lex-yacc)和纸面推导磨叽太久、语言本身特性缺失(union:int nodeTag)和__init__这种,而且但凡是个公开lib作者都爱过度设计(overdesign),很难写简洁的parser
工程界一般科普做个计算器(Node/队列指针)还是很直接的,可是不能表达变量和按语序参数,会造成很多问题(CSS支持变量后就变贼有用了)

毕竟大家开始学编程时都是按直觉的, int n; new ListSeter(){ void f(List a){a[0]=n;} } 里new了的Type实质是函数(SAM单方法接口),而SAM实质又是包含n和算式的数据(闭包),for(i0;i<;i++)for(i in 0..N) 这样都没想过吧。 框架定义,我就用,这是外国 Java 在 Kotlin 出现后如此被动的原因。 😅

你把东西写长,不会让它更”生产“或”可配置“ ”易懂“;写短,不会”更快“或”有内涵“,语义不多不少,它就在那。我觉得这是仍没见过汇编的程序员该有的认识。不知道为什么,重视语义的人很少,仿佛世界上只有语法和”JSON,YAML“这些名字,而操作它们的库API也都是孤立的,并不存在一个”概念“把所有的一切语法和表象连起来。

举个例子,S表达式就能表示HTML🙃。有人想过拿JSON保存这个吧,但是因为含大量children:[]被怼,但S表达式 (div.wtf (id xx) (a (href xx title 上级)) 就能表示HTML-DOM。
现在不少人就把它的影子当新DSL呢!我们是不是该说这是「历史倒流」呢🌝
也有许多往JS内嵌XML呢! 作为代码移植的好帮手,还真是十分有必要不独立转化而新建jsx语言呢,这样就能在单文件写html了不是?

语言对程序员来说并不遥远。它笼罩着编程的方方面面。
无论是以何种形式使用,对语言的理解决定程序员的能力,并不是做的事多了,就懂语言。

解释器实现不是不能自顶向下拆开讲,因为许多人某层面就知道那一种做法(比如刚才 zipMap 我不提出来 理解难度就++, 或者我写一大堆XXNode, 人也get不到调用和查变量的重点),他觉得无可替换(或者”这就是最快的“),而篇幅又巨大,对初学者会非常不友好
另一方面咱领域人少,一些只顾自己写开心的魔法师(人和领域是互相选择的。冷门专业冷门人)就多些,真正做科普的就少

我们从小就被教导要努力向谁看齐、要按套路管理自己的生活乃至一生,要给各种技术排名次、造『鄙视链』,可是我看到许多Vlogger,每个人都有不同的经济条件、地理位置和性格,但真的无法把他们的视频风格分出高低谁谁淘汰,他们都能让你开阔眼界——普通的生活也能如此有意思,原来做记录也可以不像在记录,却达到更好效果。

确实,技术不是最难解决的问题;把眼光放开阔,许多问题或许就是人为制造,可以从更远的地方追溯修整方案呢! #recommended

谁告诉你 combinator 和 Maybe 及类型推导,跨编译就是函数式专属的(Kotlin),谁说逻辑式就必须复杂(miniKanren),谁说{}或end 最严谨(Python),Web怎么会只有”前端“功能呢(ES6+H5API)
如果世界上存在最优的编程语言——是哪个? 最简单的/功能最多的/最快的?
许多衡量标准本身就是冲突的,先有目的,然后才有最优解。 先懂为什么,然后才看做法
我们所学的知识和理论,有多少是罔顾了原因,只有做法和自恰性的? 文档并不是只有易理解与否,还有与现实、与其他的对应性,因为编程是一件实事,目的之下一切可替换的事。

到最后你才发现,根本不存在最优解,你所看到的优秀,不过是圈子里广为流传的假象。 世界上那么多人,所谓的大牛仍是天外有天,为什么你必须向他学习呢,难道你不能有比他做得好/做得广泛之处吗。

语言不重要,思想重要。
放下排名、放下”最佳实践“,做自己想做的