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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#code #asm on x86-64, Diane's silk dress costs $89
>which registers are used for passing arguments in a Linux x86-64 system? make a tool in js, replaceTo arg{0-5}
ASMR="
subs=(kv,re=RegExp(Object.keys(kv).join('|'),'g'))=>s=>s.replace(re, key => kv[key])

subs(Object.fromEntries(
'rdi rsi rdx rcx r8 r9'.split(' ').map((register, index) => [register, 'arg'+index])
))(fs.readFileSync(0, 'utf-8'))
"


从中可以看到源码调用printf() 的汇编

>find regular file in /usr/bin/* , sort size |xargs file
find `ls -d /usr/bin/* --sort=size` -type f,d|tail -n 1000|xargs file|grep ELF

>radare2 cmd to find string "usage", and show xref in code
r2 <<<'aa;`iz~usage|awk "{print $1}"`;`axtq`' /bin/db_verify

>objdump -d, intel-syntax, no address or bytes, .text only from 0x0000113f
objdump -d -M intel --no-show-raw-insn --no-addresses --start-address=0x0000113f /bin/db_verify|node -p "$ASMR"



x86_64-CDEF/cdecl 科普:
The first six integer or pointer arguments are passed in registers rdi, rsi, rdx, rcx, r8, and r9.
Floating-point arguments are passed in the vector registers xmm0 through xmm7.
其他参数溢出到 rsp-.. 栈上,rsp+用于局部分配(right-to-left order)
<16 bytes 自动传值,也就是可int vec4
Integer and pointer return values are in rax. caller is responsible for cleaning up the stack(rsp-=.. SYSV/win32 STDCALL/包括C++ thiscall 是callee负责,这是唯一的区别)
Floating-point return values are in xmm0.


C语言可以说是汇编的附庸了,在编译后各种类型都会变成+8 +16 的偏移量,struct不能作为值自由地传递或返回,就连数组长度也记不住!
150天菜.zip
4.7 MB
#code for file in *.{jpg,jpeg,png}; do cwebp -quiet -q 90 "$file" -o "${file%.*}.webp" &&rm "$file"; echo "Converted $file to WebP format."; done
duangsuse::Echo
#learn #bash with #tool 入门+优质冷知识 😋 图为 asciinema.org/explore 。没有 #linux 的极客可打开 WebVM.io Linux Deploy; (Mac)Git Bash; winetricks; screenfetch 甚至 bashttpd; pacman/OpenRC init 基于bash shell 是类似 Windows.ps1 但使用纯文本或行IO的脚本编程语言。 每当你看见awk|sed|grep ,那就是在 #sql sele…
#Linux 与命令行 #bash
"外壳"提供了调用软件的人机接口。在 kernel.org 已对内存cpu分时分址复用、解码/dev/sdXY 分区, /sys/内设外设+网 ls {/proc,/sys/class}/net 的基础上。这是DOS.COM 所不具有的
.bashrc 和 etc/XXX.d/ 以run-command而非json注册表的方式配置设置,这既先进又落后。 rc的灵活性远优于yml,但bash的无类型,单全局表 将其化神奇😅为腐朽了(毕竟1971年老古董)
pacaur -S xonsh elvish pwsh
拥有更合理的弱类型API

您的终端通过 ANSI 清屏=printf '\e[2J\e[14t' 来控制显示效果,但对于TUI应用..有少数stdio管道不能实现的接口, https://docs.python.org/zh-cn/2/library/termios.html .iospeed.O_NONBLOCK
->py termios 如何进入非阻塞(游戏按键)模式?编写 key echo demo
->表格出所有ANSI escape,然后函数化为 clear=lambda: CSI('2J'); ...
bash连接到的tty服务器=$(fuser -s $(readlink /proc/$$/fd/0)) ,如 xfce4-terminal;ssh;tmux

— 进程管理
^C终止 ^Z挂起到jobs
htop; powertop TUI监视器
yes sir|tee just-like.dd
nohup zenity --entry --text="请输入您的姓名:" &
tail -f nohup.out
time sleep 1

#记录3态时间的后2Sum是CPU占用率 ,sys时间较高=IO密集型
jobs -l 查看pid; fg bg 继续任务$!, kill -9 $(pidof bash) 杀死

— 命令的组合 &; >< 与括号展开
{cat,echo}|grep #不要这样做! 使用'<'或arg1输入文件常量,'>>', &>/dev/null 赋值文件。尽量不要使用 >

&>fp 即 1>fp 2>&1; freopen了两个换行流文件(stdbuf -oL),就像 import subprocess.Popen(stdin=-1) 它可被读写
less -f /dev/stdin &sleep 1 &&echo>>/proc/$(pidof less)/fd/0 hi
lsof /tmp/; ss; strace -etrace=openat,getdents64,connect ls

您使用lsof即可知道进程打开了什么(网络)文件

表达式if\else
zenity --question --text="确认要执行吗?" && echo "您已确认执行。" || echo "您取消了执行。"
test -f nohup.out &&wc $_

for,case在文尾。 罕见于urls|xargs cat
a=hih;echo ${a:0:2} ${#a} ${a//h/H} $((10/3)) {01..9..2} {good,bad}boy {z..a}

hi 3 HiH 3 01 03 05 07 09 goodboy badboy..
{} 允许并列,嵌套和正择 🥰
使用可嵌套的 $() 取代`` 除了可以调用文字替换API, 还能提升组合力
diff <(echo hello world) <(echo hello bar)
less <<<Good #配合 ruby -p; node -e 胶水使用
JS=$(cat <<OK
heredoc,就像""仍能内插${} ''
OK
)

不过sh系都支持多行字符串
可以手动 tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT

— 目录管理
文件夹名/拖放 转到。不要用cd那个太古板了
mkdir -p 目录/树
ls -lh; tree; du -h 读目录,计算df大小
echo>>a.txt 记录
rm -rf * 清空$(dirs)
^xg #查看符合正择的文件
cp;mv 复制和移动到arg-1即 $_
chmod {+x,755} 设置可执行

set -s noglob 以禁用*正择
可深度遍历
,匹配多个斜杠。正则[0-9]仍有效,但'?' 变成了(.), [^\d]* 成了 *[![:digit:]] ,从find和sed的使用来看😅bash的RegExp是🤡
ls !(*.mp4)
echo **/*.mp4

替换文件扩展名(thunar -B ,不得不说单字符很脑残,何况bash连对象键值都停留在get/set函数名) https://wangdoc.com/bash/string#搜索和替换
fp=a.x.mp4; echo ${fp%.*} ${fp##*.}
echo ${fp/.*/} ${fp/*./}

a.x mp4
a mp4
for fp in *; do [[ $fp =~ \.png$ ]]&&ls "$fp"; done

自至剪贴板
a=$(xclip -selection clipboard -o); base64 <<<$a|xclip -selection clipboard

练习:封装这些功能为函数或basename式CLI工具,加什么参数你看着办,这幼儿园Perl我看着就难受

— sh变量
不支持str和float算式,支持?:
pargs() { echo "$@"; }
pargs x y #x y. 不像argv它不含$0
echo $PS{1,2} #为什么大佬教你要 "$var"呢?试试在文件名里加空格或 echo $(cal) ?牛逼啊,还能SQL注入了!默认语意这么脑残
IFS=":" # read分隔符为冒号, 遍历可执行注册表
for dir in $PATH; do
echo "$dir"; done
export PATH #bash连字符串变量也不默认传给子进程
#有无屏幕, 其实 .bash_login 就是tty-only
(xdotool sleep .1 search --name tty windowsize 100% 100%)& alacritty
[ -z $DISPLAY ]&&startx /bin/sh atty.sh

read id; ${id:=Peter}
read id; ${id:?Oh no Peter}
#不建议用 declare -i c; c=1+2 或let=运算,可以
((a=1,b=2)); array=([2]=c [0]=a [1]=b) #读取 "${array[0或@]}"



— 权限
您的系统通过chown和setcap来管理特权,所有文件通过 umask: ugo(user grp other)三权分立,一般为 644, 755(=rwxrxrx 对于目录x允许进入)
6(rw-)即是位旗 0b100+0b10+0; echo $[2#100+2#10],644以此类推
特别地,wheel 用户组(类似win/droid的SYSTEM) 可使用/bin/sudo 来鉴权到sudo的所有者root。为了防止 LD_PRELOAD注入应使用 visudo 修改配置
find / -perm /4000

列举所有自鉴权模块如su
sudo setcap cap_net_bind_service=+ep $(command -v python)

#允许bind 80端口
# cat /etc/{,g}shadow /etc/{passwd,fstab,sudoers,ssh/sshd_config} 只有root能查看。权力越大责任越小,rm -rf /* 😱享受特权吧!

— 古怪的语法
先前学过java的大佬,会觉得 if-fi case-esac for-done 比Lua和Matlab还啰嗦,这是因为bash采取了shlex 而且和TeX一样不懂变通
if [ ]; then, for in ; do 更像是2条命令(do eval字符串 done) 而不是“块”, forkBomb() { sleep; } 尾分号同理
bash 区分命令和计算的$()也很含糊,但在pwsh上都是 ()
duangsuse::Echo
— CLI程序服务 getopts; complete 用于获取短参数和提供补齐。少数人用while shift/read;case 来解析 还有一个select in ; do,和py2 print 是异曲同工之败笔,请 ->展示zenity的所有功能,并生成一个简短的MC风格的文字冒险 #!/bin/bash while getopts ":n:s:err" opt; do #?未知 :空 case $opt in n) n=$OPTARG ;; s) s=$OPTARG ;;…
#py #code snake 贪吃蛇,最近很忙放着待改
import termios as TTY,copy, sys,time, numpy as np

from contextlib import contextmanager
from dataclasses import dataclass as d
@d
class tty:
fd:int
@property
def Is(_):return TTY.tcgetattr(_.fd)
@Is.setter
def Is(_,v):TTY.tcsetattr(_.fd, TTY.TCSADRAIN, v)

@contextmanager
def swap(x,r, f):
v=r.fget(x)
try: r.fset(x,f(v1:=copy.deepcopy(v))or v1);yield
finally: r.fset(x,v)

sdf=lambda w,h,f:np.fromfunction(lambda x,y:f(x-.5*w,y-.5*h), (w,h))
sdQuad=lambda r:lambda x,y:abs(x+y)+abs(x-y)-r
def snake(a=sdf(15,15, sdQuad(10)), fps=2):
a=np.vectorize(lambda P: 1 if P>2 else 0)(a)
n,m=a.shape; P=0;dP=1
kbd={'a':-1,'d':+1,'w':-m,'s':+m,}
def ADWS(a):a[3]=a[3] &~ TTY.ICANON|TTY.ECHO; a[-1][TTY.VMIN]=0
def f5():
nonlocal P
P+=dP;a[P//m,P%m]=0
print(a)
with swap(tty(0), tty.Is,ADWS):
while True:
k=sys.stdin.read(1); dP=kbd.get(k)or dP
print(f'\x1b[{n}A',end=''); f5(); time.sleep(1/fps)

snake()
#learn #kt Benny霍评论区
协程 async。自动传回调、var都打包到其class因为,比如传给sleep()后自己要return。协程对象就比()->闭包多留个switch(nthStmt){}

把sleep()外提为赋值语句,以保留和恢复调用栈而已,linux单核调度多线程,甚至你调用IO时为了鉴权,也会这么干。 cat|head 不就会await您的键盘吗? read()就会suspend 1个C语言的“有栈”协程。
之所以要async,只是想节省pthread_create,因为你要拿mainloop去poll(定期/卡http的轮询) 触摸屏事件,设备资源是独占的。这和内核驱动(/dev/WebUSB) 才能导致死机蓝屏是一个道理

如果系统,比如Web APIs吧,只提供回调而禁止while(1),哪怕只支持epoll(查看监听)/select(poll多项),就根本不存在线程一词 -就像C里你并不知道read()本质上await在pipe前“生成器”的write()
--也有人叫它yield,那是因为我们不能靠return写入“文件变量”、不能重赋值函数参数以返回多个值.. 为此jspy还发明了“async*()=>生成器”..
完美复刻UI层State(val).onvar[]的轮子呢!可惜是难用难复用的阉割版。

VSCode只加两个js线程,就能运行得很稳,这难道不是App设计的常态吗?难道那些小程序比code更“架构”?
至于免锁或基于资源.transferTo()的多线程,WebGL/numpy/MapReduce(ForkJoin) 不需要重造OS 1Dispatcher:N Continuation(该叫class CPU: ()->isFinished吧)的轮子配什么池化,就能实现前后端们无法想象的性能提升。

ES5的 yield cont=>setTimeout(cont,1s) ,由awaiter链接timeout和g.next,已经是免编译协程API的巅峰了,Promise.then 只是省得你传cont回调。 当然,timeout也可能返回cont=> 所以then要能接受async()

另:JS是视 fetch(u,{abort:Signal}) 取消任务的,我不认为app里会需要一堆 coroScope{} 这样图文不符的结构。kt在UIUX界敢能和H5相比么?为什么语言多项功能,app的功能却少的可怜!

kt的结构化并发不比Go的WaitGroup(semaphore)有用,但新词一大堆,初心全忘了,开始比java还八股了。真可笑,屠龙者终成恶龙
那些比Promise更繁琐的,是毫无语意的知识,迟早被py AI自动完成。看来科学界也不喜欢代码圈整这些无聊的class

就问 https://python-future.org/ 2to3这么聪明又简洁的lib,java人们啥时候能学会?态度问题,不是智商低 #statement

协程线程进程,都是Job
jobs的管理上,除了^Z SIGHUP再 fg bg 恢复,内核还支持swap(整个系统的)内存页到SSD,甚至用CRIU直接把进程快照为文件。 这样的快照不仅能多拍,还可通过网络传输,简直易如截屏,又像 Termux.dev / Waydro.id / webvm.io 那样神奇;然而这样超越运行期的“时间魔法”,90%的编译器根本做不到,只能用reflect或asm模板这样的残次品搪塞;同理90%的语言里“函数值”都没有相等性--所谓闭包“值捕获”却并不能自动内联JSON,所谓RPC,protobuf还不如微软的COM,pwsh.NET普适
#os 在这一点上可比 #plt 的孤岛、围城,先进太多了
https://t.me/dsuse/19341

https://kotlinlang.org/docs/coroutines-overview.html
https://github.com/youngyangyang04/TechCPP/blob/master/problems/为什么用户态和内核态的相互切换过程开销比较大.md
http://cht.sh/podman

podman run -dt -name cnt busybox /bin/sh -c 'i=0; while true; do echo $i; i=$((i + 1)); sleep 1; done'
podman container checkpoint cnt
podman container restore cnt

https://t.bilibili.com/948850441406382096
#think #web #tool
https://cssgridgenerator.io/
https://crocotile3d.com/
https://fixupx.com/Oroshibu/status/1808500235263418441?t=BtGGBHj9jnN2AReHW2VTWA&s=19
三視圖?

有趣的建模工具
帅啊!
螺莉莉的黑板报:
(๑•‌ㅂ•‌)و✧
https://dataset.wav.pub/

https://brython.info/demo.html
https://github.com/Distributive-Network/PythonMonkey
#py
螺莉莉的黑板报:
https://github.com/baskerville/plato/blob/master/README.md

你们 rust 真是啥都能干……

https://www.sea-ql.org/SeaORM/

这东西好用么……求教……

https://gitlab.com/coolreader-ng/crengine-ng

有趣的引擎

https://chinese-font.netlify.app/ font
https://typst.app/universe/package/bob-draw
#svg

https://ivanceras.github.io/svgbob-editor/

#code
duangsuse:
大量复制粘贴十分抽象
list有那么难用吗
难道你没注意到近十行只变了1个参数
AIGC也没脚本化得这么严重吧

我看还是用list first!null好了,这么八股文…… 大家现在都是用get null取代预判has的

这种到处预判的风格,很像你找大佬问问题,先发「您在不在」,他只好回个在,然后你不在线……

表达式化比你想的要多哦:

>Spring如何把 @Autowired T xx; 换为 var xx=find(T.class)

var Ts = [T.class].map( applicationContext::getBean);

你在class{}里加那一堆定义,如果只引用了一次,就完全不应该引用。 到底都是要查bean的

从code smell来看,只使用了1次的变量名是无效的;如果只是为了易读新建变量,只能证明你的helper fn命名的有问题

kt已经有!! 了,还想要更多
Java 一大特色,注解属于元数据,和函数调用有重大区别

duangsuse:
那这是定义“随用随扔”变量名的理由吗
函数和变量是这么用的?
java以省略[""] 为由引入太多常量复杂度的优化了,都要所谓框架来解决

纯粹是make compiler happy,把一个schema弄成它能读懂的class,然后再强转Any来构造class而已

js里一个字典让java用就是这么麻烦,其实能用几次呢? init完就扔了,根本不是性能瓶颈。

注解的本意,应该和py的 @decorator 一样,是接受class元数据的编译期函数才对

而不是等到运行时才去查什么field有哪些@属性 然后逐个.set()

要动态生成一个类型,来获取注入,简直无理取闹。 明明就该在编译期产生Registry.get&fillNew的样板函数

这是属于既把元编程的路封死了,还不让基于注解的注入框架提供统一的“反射”方法

其实jawa懂这个道理,但它偏偏就做得很烂,就会个@Override
duangsuse:
为了编译速度这也太幽默了,其实,jvm作为栈机 基本就是带类型签名的GNU dc计算器,不需要什么编译优化

如果递归下降一遍,校验下类型 生成个push call 就能花什么编译时间,属于是用PHP的方式搞算法了

而且javac的能力还远没有到c预处理器的程度,为了优化? 我看是他们不在乎程序/类定义的优雅性

什么序列化啊,也没有做规范,和py能 import json,yaml,toml,marshal 能比?就一个用来RPC的ObjStream,还被业界遗忘,哈哈

汤姆猫是大专必学

虽然汤姆猫的Biz程度也就比Node http-server强半点吧

所以问题就是Result类型为何没有重载 !!, 让它看起来仿佛只是带有错误消息是null

凭什么!! 只能校验 Type? 呢?
assert也是乐观/悲观路径
Exception也是,为什么不能一起判定了?
还非得搞个ifEmpty, ifBlank.. ifNullOrBlank..
莫名其妙

duangsuse:
这不是废话吗?例如买30天大会员,肯定是30* 24*60*60秒后失效,这才是世俗意义上的电脑时间

看到py关于时间和日期/时差有3个API
我就觉得抽象

audit就是一个不懂AOP的,其实unix可以靠strace审查syscall,win32的 sysinternals.com 也有进程日志功能

与其自己搞个无人知晓的轮子,不如封装别人的,两全其美
把OS的活都包揽了,难道py是要运行在Ring0把内核驱动都带上? 那必须支持啊

绷不住了,抽象程度直逼jawa

一开始就不该搞所谓orNull
默认 first{}!! 就够了

我在js里都是把Error视为object返回值的特例,和null是一个意思
这样就不存在什么orNull orElse的,catch表达式也免了

就是语言设计者对值体系的理解不过关,例如NaN就是numbers的null才对,而不是什么number?
这样才能用统一的方法去报错/换默认值

可悲的是一开始就没把悲伤/快乐路径当问题啊,真是异常搞心态

duangsuse:
幽默IDE
完全相信它的API有一大堆根本用不上的class
忸怩作态的软件没必要去维护

kcp是这样的,可 import ast 自 https://python-future.org 就没变过😋
py只是用:隔离一个表达式先于=执行,就实现了高贵语言们的静态检查

既可以用于静态分析,也能在运行时查看f.annotation ,完备的数据不需要反射

btw. 大佬应该会做一个DSL
Message.invoke{ id==mid }
Message.select{ id==mid }//多项

可是这种写法才是真正的SQL逻辑式

既然Msg(id=)能构造数据, Msg{id==} 就能查询
这不是很合理么 #kt

很简单,如果做得太标准,以至于移植到任何一门语言里都没必要修改的话
就没人给官方docs贡献流量了

duangsuse:
https://www.liuwj.me/posts/ktorm-introduction/
🤔 一个SQL函数.xml codegen 能被吹爆,还有人卖课是我没想到的
ES6里一句 sql${} 解决的东西,哈哈

「没想到他文化程度那么低」……

怎么会呢,语句能缓存,再怎么也比一次加载完dao好

你要是不喜欢,或者不相信语法糖有缓存,可以做成生成函数的形式
例如
updateId=f=sqlFn2{a,b-> Pair{B/b, A/a}}
f("bye",0)

所以说,如果你不相信DSL能被缓存,可以转为生成sql函数的形式啊

这不是MyBatis++ ?

https://github.com/JetBrains/Exposed/blob/main/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt#L184

我只能说,缓存键要么是调用点或次数
要么是函数
似乎很难单独缓存DSL对象,除非对它们的构造器
幸运的是, key eq x 里x的修改能缓存,因为它是参数

https://jetbrains.github.io/Exposed/frequently-asked-questions.html#q-how-to-get-a-plain-sql-query-which-will-be-executed

https://stackoverflow.com/questions/74821893/postgresql-arrays-instead-of-extra-table-in-a-many-to-many-relationship
涨姿势了,以后 1:N用数组json N:N用join

duangsuse: #fp
要是kt能允许编译期生成一部分表达式,就没这问题了😅😅😅

可惜啊, unquote{bash(q(trim("trimedStr")))} 这当然是lisp的专利
其中q() 被生成为一个字面量,就像闭包捕获:
fun bash(s)=trim(s).let:
paste {system(it)}

并没有所谓的编译期,因为编译器能访问所有lib API


0开销不是瓶颈问题,但事关语言的脸面

明明就很有用,可被一些人理解为「并非瓶颈的东西」
然后被rustc拿来完魔法

要我说他们就是傻屌,只不过是把闭包「捕获」的实现方式,改为内联字面量(unquote)
就能轻松突破编译、运行的动静边界,根本没有引入任何新API ,没有什么循环展开和 kotlinpoet javapoet的区别

他们做成什么样了? 正则的缓存还不如py的拿dict查😅
#kt #code 😊之前,v8 blog说Promise就是Continuation(含续体的回调),我还觉得多此一举
和Kotlin“强大”的API一比,我却要变成ES6吹了。Web的先驱者们简直是先知啊! 代码越复杂,成品功能越简陋。这就是为什么安卓app体积不断膨胀,功能却越来越卡。

interface Promise_<R,T> {
fun then(ret:OrErr<R>) //delay() 后应该这么做,那之前只需调用它并return。它通过cpu{}排队,另一种排法是yield Promise
//launch(ctx=Main+CoroName("val")) Map状链表DSL。Job等元素
var cpu:(Runnable)->Unit; name=""
fun go(:T?):R
fun stop(:ErrStop)
stdState=0,1完成,2取消
//不要使用截获器和Key环境变量。组合优于继承,go 的WaitGroup比不伦鸡肋的scope明确多了,Android的curl比js的fetch流更复杂吗?
}
type OrErr<R>=Or<R,Err>, Err=Exception
val OrErr<R>.!!: R
sealed Or<out A,B> {
data A(:A) data B(:B)
fun as(A->R?, B->R?={null}): R?
val A:A? val B:B?
}
fun T?.as(R, T->R):R
fun T?.as(T->R):R?


😊顺带把阿K没有统一的err/null错处也搞了,还要什么 o?.x?.y ?: 1
https://www.bennyhuo.com/book/kotlin-coroutines/12-why-so-called-lightweight-thread.html

上面说协程=Thread.asCallback() 只是一种go/lua的罕见情况,好理解嘛。
kt里协程是通过retAddr()作为参数,实现的链表化调用栈,其第0项一般是 runBlocking{}或thisCPU.nextJob
这样可以在主循环注册任意个delay()或flow{}的回调,优化 Promise.all。这是虚拟线程所不擅长的
https://www.bennyhuo.com/book/kotlin-coroutines/13-implementations.html
duangsuse::Echo
https://ray-eldath.me/programming/three-important-ideas/ #statement #PLT Ray: 我的一位朋友如此评论这些文章:他说真正理解抽象的唯一方式是通过抽象本身,而不是通过并不准确的类比。 「为了充分地("有用处"地)学习这些抽象,你必须去学数学,而不是通过一些糊里糊涂的文章,它们除了类比还是类比」 Dr: 要找到 “哪些代码遵循此抽象” 并不是必须的。像 Monad 这样的概念是非常抽象和通用的:它是一个描述了一套广泛的编程模式、数据结构、库和…
#PLT #learn 文中提到一个Futa对应关系(第一类二村映射 first Futamura projection), 展开讲讲还蛮有趣 🙉
首先,js人都会写计算器的,和 echo input/server 一样的难度

1+2*3
十(1, X(2,3)) -7

十=(A,B)=>A+B

这被称为「前缀式polish notation」,是Lisp的国是
教个小诀窍:js里函数只是一种字面常量,可以被for生成
Object.entries("十一Xノ").forEach(([i,x])=>
this[x]=eval(`(A,B)=>A${"+-*/"[i]}B`))


为了更像“语言”,可以用列表(进一步就是"1+2"的代码)实现语法,便于糖化
Eval([十,1, X,2,3]) -7
Eval=([f,...x])=>(!f.call)? [f,x] : //基线返回两项,递归就都是两项
(([A,b]=Eval(x),[B,c]=Eval(b))=>[f(A,B), c] )()


Monadic递归下降是这样AbBc的,因为不能右移流指针。不如逆波兰好看!不过这种程度的递归可以学学。

再看下「解释器interpreter」比计算器强在哪: 能够“在调用时传值”,也就是要有 argument[0] 这种“环境变量”
很厉害!现在有常数外的“语法”了,有变量了,高阶了!或许你需要学动态作用域(原型链?)、调用栈call-ret、惰性求值如&&|| blabla,还有深不可测的编译优化呢!

不就加一个箭头么。
十=(A,B)=> (env=>A(env)+B(env)) //现在知道为啥该用for生成函数?
Lit=x=> env=>x
Arg=i=> env=>env[i] //PHP写作 $x, 模仿bash的$1~$*
Fun=(n,f)=>f(Array(n).fill(0).map((x,i)=> Arg(i)))


env被称为运行时,它可以是JVM, import dis 或者别的bytecode解释器,这能减少tree-walk对递归栈的频繁依赖
这种 formSytanx.bind(consts=lit/arg/global/Types..) 的"部分传参"函数,称为编译器,而它的返回就是classFile等类型。
编译器并不需要与DSL这些技巧隔离,如果我们把 env=>x 写作 JSON(x) 而 env=>env[i] 写作$i ,既 Lit=x=> gcc? CBor.dumps(x) : (env=>x)
以这种人类或机器可读的结构序列化一些函数被"bind"到的lit,就得到了对应的代码。jvm的 lconst 1, aload_0 this参数, iadd (2->1)甚至是自动分配参数寄存器的!
https://www.yinwang.org/blog-cn/2014/01/04/authority#:~:text=partial%20evaluator。其实并不是特别神奇的东西,只需要在普通解释器里面改一两行代码就行,可是有人

二段求值。代码是流动的数据,内存是暂停的程序。本文甚至比赢王更直观: https://www.yinwang.org/blog-cn/2012/08/01/interpreter
定义个“元循环加法”吧?
十1=Fun(1, ([A])=>十(A, Lit(1)))
十1([232]) -233

//[Lit(f),x] 补丁下Eval"解析器"。计算器、解释器、编译器间,其实并非泾渭分明
Eval([十,1, X,2,X,1,3])[0]([2]) -7


如果你乐意,还可以支持基于全局表的递归 fib=f(x)=x<2? 1 : f(x-1)+f(x-2)
这一切都不会突破以上的定义框架。 If 不会,Call(f,x-1) 不会.. 这就是java的反射嘛。
我不想再写什么了。 我看过许多“编译原理书”,他们连这个=>都写不明白。 更何谈用Visitor实现(反)序列化 这些既理论又实践的approach
#haskell data Val=L Int|Op Char Val Val deriving(Show)
(Op '+' (L 1) (Op '*' (L 2) (L 3) ))

这类基于list或class{子类多型} 的 Eval(e=^^, env={proto:{..}}),与本文使用的闭包法是等价的。「闭包是穷人的对象」,Promise 给它暴露到了 obj.then(Continuation)

> 高阶的思想或许是本文的所有思想中最为重要的那一个 https://ray-eldath.me/programming/three-important-ideas/
你们知道函数的函数、类型的类型、语言的语法,却难以创造「语言中的语言」—跨越用途与界限而一致的语意。
我看numpy和 taichi-lang.org 就用的很好,比LLVM好一个世代
顺带一提,上文还使用了 Tagless FinalDe Bruijn 索引 😇 。只是…… 你甚至不需要知道它们的名字。([A])=> 经常被实现为KV["A"],但点明它的本质,却比写解释器更简单!

说到底,元编程也只是编程。就像“学会学习”只是一种策略,它对学习而言,并非例外情况。难者,不会也,譬如在谈"bind(x=1)后函数值字面是否改变"时提起「颗粒化curryArg」 当然会让人迷糊
node,graal会编译js,jvm代码(这也是为何Chrome页偶尔会segfault); JVM会使用汇编模板+JIT 的混合式优化,Cython则把“甜妹语言”翻译到C,LLVM则是个伪装成NodeGraph虚拟机的codegen
如果只用"是否该调用javac"来区分语言,认为C类型总比python更快的话,你会发现程序员钟意的都是freak!

宏,macro码可揉,是传入与生成class{}等字面的函数。和+-*/一样只是函数,而函数、类型,只是值,别被“静态分析”骗了,它们送你的class只是病态类型。
入,lambda栏目答,看x,A,B等栏目回答的算式
这点篇幅放前言都觉得寒碜吧? 可就是没人做到啊。 扶她投影?不知道的还以为是HP projector 的娘化版呢。。
PLT能对dev点化到的可谓寥寥, 但100%都是必要且急需的知识和"抽象",像Prolog的模板与响应式html编程("FRP") 什么的。 Monadic错误处理我不想吐槽什么,只能说不怕不识货,只怕和Kotlin比!

跑题了。当然,聪明的你会发现Fun的返回违背了"基线指明了递归的类型"这一原则,没生成 env=>
那C语言函数指针是这样的,env由*rbp[0:2]=[retRbp,retAddr]这些CPU变量提供,但JS里的闭包可以从env偷变量(Var作为值,mut ref),所以说「闭包是穷人的(单方法)对象」

C里还有"函数符号",那是由ld.so实现的全局表,让.o对象能先被mmap到任意地址,再去回填calls
真正的那个全局表叫 $PATH: ,以及没定义main的对象的 $LD_LIBRARY_PATH 。
#js #code https://blog.axlight.com/posts/how-valtio-was-born/ jotai作者的博客

React 虽然很流行,很“FP”,但我不得不指出,它对“不可变”或者说「静态」的理解是有问题的…… 这点上居然输给了被它打败的MVP,MVVM等八股文

div(input(n=0)) 包含可变状态吗? 许多人觉得n是一个变数,那么, class ModelThis(var n=0) 凭什么能被称为「静态类型」呢? 视图的模型,到底是静态还是动态?

React 没有意识到,作为一个框架的职责,是维护JSON所对应的HTML模板;而函数式的作用,仅限于用mapfilter取代 forif 这些缺乏表现力的套路
“不可变”并不包含更多的超能力,实际上,它只是对「静态结构」的误解。JSON总是可变的,但它的Schema(struct,'type':union..)则永远是固定的!

集合类型,也包括函数,都能包含树洞。只要你定义了字典与HTML里树洞间的「对应关系」,并不需要什么设计模式就能秒杀各种UIUX。

>https://gist.github.com/duangsuse/c2703fae87c92826a482ef2dd9f523c6#file-note-woj-js-L35
口=holey
let A=口(0), B=A(x=>x+1)
A(2)

JSON.stringify({A,B}) //B: A+1 永远成立,无论保存在什么结构里
el(doc.body, el("div",{onclick:A((x,to)=>+x+1)}, el("input",{value:A}), el("u",B)))


这样就是一个Counter了 (代码比较烂就不贴完了,许多相关数据结构都还在设计中…… 相信最终会很优雅

我在React里看不到这种“口->口”(对象和箭头)构成的范畴,所以说它纯函数在哪呢?

如果React是基于关系式列表字典设计的,它只需要请 cage({n}) 把app所用到所有的洞锁起来就可以达成“状态树持久化”
何必解决什么View可变性的挑战?

btw. 冷知识: F12 是怎么显示函数源码 ƒ Object() { [native code] } 的? 🧐
https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts
https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/panels/event_listeners/EventListenersUtils.ts