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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
Forwarded from duangsuse Throws
笑话:斐波纳奇汤:今天的汤=昨天的汤+前天的汤(自某期《第一时间》笑话部分) #Math
duangsuse::Echo
虽然我连 GAWK 都不会用 UPDATE: 上面的 "(.*)" 应改成 "(.*?)"、<*?> 和 <*> 的意思不一样,它表示『最小匹配』…… 也就是说 takeUntil 到下一项 '"'; 以上 Regex 会把 <abc><123> 弄错,没注意到是因为 <.> 不匹配换行符,感谢细心观众 https://t.me/bystartw_tw. refs
关于正则表达式说几句 #learn 因为这次我错了……(气死,怎么能够犯低级错误,虽然我也没高级到哪里去……)

正则表达式呢…… 就是一种描述『模式(pattern)』的语言
比如说,你大爷喜欢养猫
你大爷有四只猫,分别是黑猫(B)、白猫(W)、花猫(H)、龙猫(L)

—例1
他今天给你带来一只花猫
明天是黑猫
后天是白猫
大后天是龙猫(怎么有点奇怪的东西混进来了……)

你大爷的情绪很波动,所以你需要根据带来猫猫的顺序,判断他情绪的走向。(怎么感觉这个例子举得很是戏谑……)

上面的[例1]可以用我们的『正猫表达式(Regcx, REGular Cat eXpression)』表达:
/HBWL/ — 顺序(sequential)

不过我们比单纯的 "ABCD" 四个字符走得更远,因为可以存在变量 — 而且显然一个『位置』不一定只有一种情况
比如说,你大爷经常带黑猫或者白猫来表示他的心情不好,而你不知道可能(or)『匹配』到的是哪种
/B|W/ — 可能性(or)
花猫或者龙猫表示他的心情好
/H|L/
「括起来」就是给这种情况一个名字,然后我们可以在该『顺序』接下来的时间里以名字使用这个东西
/(H|L)/

我们假设(很平常地):
你大爷情绪波动的时候会带来与昨天不同的猫猫
因为你是有记忆的,所以你只需记住他昨天是带来什么猫就好了
但是有一点:如果我们每次把 (B|W|H|L) 写全就太麻烦了,于是就有了简记法:我们称之为『猫类』
所有猫就这么表示吧: /🐱/
/(🐱)$1/
这就是表达两天里带的是同一种猫($1 是匹配上次的猫 (🐱)),情绪不波动。

可是这只能判断两天里的情况啊!?

于是我们得引入重复的『模式』
不过有一点 — 除了处理现实生活的情况,你可能还要应付你大爷带猫的记录,某个月的记录有可能(因为你的懒惰)是空的
换句话说可能一个猫也没有。

又或者,你尝试匹配的某个模式期待的是 B 黑猫,但是你看到的却是 W 白猫。
这是经常发生的。

/B+/ — 一直是黑猫,且至少有一只(some)
/B?/ — 一只黑猫,不过也可能没有(optional)
/B*/ — 一直是黑猫,也可能没有(many)

/((🐱)\1)*/
就是这个意思了,它会匹配 BBWWHHLL 这种…… 不过这其实不叫『情绪平稳』
/(🐱)\1*/

BBBBBBB; WWWWW; HHH…… 这才叫

== 那么最基本的(顺序、可能性分支、重复)模式就在上面了,下面来说一些表达性的东西,就是 Regex 了。

不过 Regex 是解决字符流匹配的问题,不是猫流(哈哈哈)匹配的问题……

0. 有些项目(item)很特殊,比如 /./ 匹配单个字符、/^/ 匹配一行的开始、/$/ 匹配一行的结尾
一般他们被用于顺序匹配,比如单行 emmm: /^emmm$/
1. 当你想表达『可能是一类』的时候,你可以:
\猫类名
字符流也可以……
\d digits "123"
\w 像 "hello_world123" 这种
\s \S 空格和非空格(基本都是大写逆命题的form,\d \D 也是)

3. 也可以直接用 [...] 区间:
[a-z]
[A-Z]
[a-zA-Z0-9]
[...] 里面是对集合(字符的『类』)所有元素的穷举描述
a-b 这种语法是只有 [...] 里能用的,它表示 a~b 区间里的所有字符…… 字符都是有自己编号的
Unicode 里这个标号叫 code point
是一种枚举(enumeration)!

/a?=(b)/ 是 positive lookahead,意思是我们要 a,但是只有在b前面时才「匹配」
/a?!(b)/ 正好相反,只有不在 b 前面才匹配
这被称为『先行断言』

然后懒得说了…… 😕
https://regex101.com/
Regex 的语法可以很无穷尽的,一般都是以 PCRE (Perl Compatible Regex) 为准
下面你们可以稍微学得深一点 — 『正猫表达式』的确是存在的!

……如果不存在,那就造一个。
我们使用的是目前虽然看起来无bug但是很麻烦的Parser.kt库。
……算了好像重新写工作量也不大,毕竟这个架构是简单

— Regcx cat class
class of cats in: [BW]
class of cats not in: [^BW]
class of cats in|(not in) range: [B-W]
class of cats in ranges: [B-WH-L]

— Regcx wildcard
any cat: 🐱
any nil record: ✖️
peek a cat: 👀

— Regcx structure and capture
seq: HBL
or: H|B|L
capture: (H)

— Regcx quantifier
some: H+
many: H*
optional: H?
exactly-count: H{3}
greater-count: H{3,}
range-count: H{3,6}

— Regcx anchor
begin of records: 📝
end of records:
武器是难用的、玩具是方便的,我还是一直这么写玩具算了……
突然感觉这么弄很没意义
duangsuse::Echo
下面你们可以稍微学得深一点 — 『正猫表达式』的确是存在的! ……如果不存在,那就造一个。 我们使用的是目前虽然看起来无bug但是很麻烦的Parser.kt库。 ……算了好像重新写工作量也不大,毕竟这个架构是简单 — Regcx cat class class of cats in: [BW] class of cats not in: [^BW] class of cats in|(not in) range: [B-W] class of cats in ranges: [B-WH-L] — Regcx…
Cat = 'B' | 'W' | 'H' | 'L'
Factor0 = '.' | '✖️' | 'x' | Cat
CatClass
= (leftSQ hill Factor0+ rightSQ)
| (leftSQ Factor0+ rightSQ)
Struct = Seq | Capture | Or | Repeat | Optional
Seq = Factor {Factor}
Capture = '(' Factor ')'
Or = Factor {'|' Factor}
Optional = Factor '?'
Repeat
= Factor '+'
| Factor '*'
| ExactRepeat
ExactRepeat
= Factor (leftBR N rightBR)
| Factor (leftBR N comma rightBR)
| Factor (leftBR N comma N rightBR)
Factor = Factor0 | CatClass | Struct
Regcx = Factor

这就可见是一个 LL(1),不过其实我更喜欢PEG,emmm。
突然觉悟出『完全面向对象』设计不好……
duangsuse::Echo
突然觉悟出『完全面向对象』设计不好……
解锁新成就——整个项目,都是笑话x2
黑猫白猫什么的说说就好了…… 非得写那么多太当真hhh
This media is not supported in your browser
VIEW IN TELEGRAM
#linux #sysadmin 小科普:(简易)Graphviz 的 dot 怎么使用呢?
digraph J {
node [shape=record];
0 [label="江泽民"];
1 [label="胡锦涛"];
2 [label="习近平"];
0 -> 1 [style=solid, label="蛤"];
1 -> 2 [label="🐻"]
}
然后
dot -Tpng a.dot -o a.png
咳咳。那我就真说一下 Base64 编码的问题了。 #CS
这个问题是我看一篇小说《数据的尽头》注意到的,作者是JavaScript/PHP程序员。

讲解的时候犯了一些低级错误,我就不说了。

下面我编写的时候不会考虑性能问题,所以数据模型上会有很大出入。

Base64是什么?

/** Binary `2**8` 0-63 */
enum class Radix64 {
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`,
`+`, `~`; /*'/'*/
companion object Read {
fun from(ordinal: Int): Radix64 = values()[ordinal]
fun from(c: Char): Radix64 = when (c) {
in 'A'..'Z' -> from(c.minus('A').toInt())
in 'a'..'z' -> from(c.minus('a').toInt()+26) //size[A-Z]
in '0'..'9' -> from(c.minus('0').toInt()+26+26) //size[A-Za-z]
else -> when (c) { '+' -> `+`; '/' -> `~`; else -> throw Error() }
} }
} //padding '='

typealias Base64 = Array<out Radix64>
interface Base64Coder {
fun from(orig: ByteArray): Base64
fun to(code: Base64): ByteArray
}


就是这样。
2**(8*3) = 64**4
2^{8*3}=64^4

可以使用 4 个Radix64来表达3个byte。
如何换算,才是问题所在。

那么怎么换算呢
就是进制换算啊

base=2 换算到 base=64 嘛。

都是用 2**6 速查表的…… 因为2**6直接对应到了Radix64
问题是编码后长度会有多长
因为加了padding我们认为输入长度肯定是
(n+3.dec()) / (3*4) + 1

首先想想padding是怎么用的
就是在最后一个单位(3byte)不足时,为1byte补两位、为2byte补一位的 '='

讲不下去了,实在想不出比率比率……
学不会算法尤其是看不懂数学公式,找不着等价算式的人废话最多
虽然数学不好,但其实也可以勉强弄一些逻辑性比数学性强的
比如说,一个深度为 N 的满二叉树,我知道它有 1+2**(N-1)个节点,而这个式子我能把它对应到二叉树的图形上(模糊地,因为这个抽象就是模糊的……
比如说,稍微想想还是能够想出Category甚至Functor里面的样子的,可惜我看到的是一堆模糊的东西,没有态射因为我只知 2=0.inc().inc(); 所以范畴就是一堆模糊的对象……
我实在没有办法,因为我就是数学不好。

我说的数学不好主要还是算术实在是做不过来,这样一些我需要枚举/计算一些东西的时候就会出差错或者至少影响我的思路
比如说,假如有一个 val a = if (p) 1 else 2,然后
下面哪怕是一个简单的 val b = a * 3
我根本没办法想出 p 不 p 时 b 有啥区别
可能稍微花个5秒我能想出来,不过这样的速度面向排错编程肯定是用不上了……(可能要尝试N遍来找一个可能的修法

其次是抽象上也不过关,比如说我经常忘记 1/2 是啥意思,好像它和 2/1 没区别一样。
实例就是,a*n/k 比率计算我都会觉得有点莫名其妙,要是再复杂一点的公式就GG了。
等式性质(比如 a*(a+1) 什么的)上可能勉强一点
#book 这些是我在学校里想起曾经看过的书……
感觉还是没有什么进步啊
果然是这样吗?

— 注,书名作者名全都是我记忆里的版本,不对正确性作出担保
《ES6标准入门》by 阮一峰
《Kotlin极简教程》by 陈光剑
《The Little Scheme — 递归与函数式的奥妙》 虽然现在表述式(过程式,命令式)、定义式(函数式,声明式)、逻辑式(描述式)都不流行hhhh?就是那个 The Little Schemer 的中文版
《嵌入式Linux系统与工程实践》
《完美应用OpenSUSE》by 何晓龙
《算法图解》 Grokking Algorithms
《算法I-IV(C++实现)》 Algorithms in C++ I-IV: Fundamentals, Data Structure, Sorting, Searching by Robert Sedgewick
《Ruby元编程 II》 Metaprogramming Ruby II
《深入剖析Ruby虚拟机》 Ruby under a Microscope by Paolo Patrick
《CLR via C# 中文版》 CLR via C# by Jeff Richester
《快速轻量级JavaEE开发》 Continuous Enterprise Development in JavaEE
《Qt5.9 C++实战》
《操作系统笔记2019》
《一本通 二级C语言》
《软件工程导论》
《有趣的二进制》
《Internet原理与技术》
《手把手教你FPGA设计——基于大道至简的设计法》
《职场新生代 嵌入式600问》
《小白都能看懂的Python大数据分析》
《LLVM Cookbook中文版》 LLVM Cookbook
《深入分析GCC》
《深入理解Java虚拟机——JVM高级特性与最佳实践》by 周志明
《PHP内核分析》
《Lua设计与实践》by codedump
最后还有一点我做的笔记 #CS #sysadmin #linux 我懒得详细讲了,照本宣科当人肉 OCR……

AWK -F
/regex/ {}
BEGIN {} END {}
gsub(/(\d)/, $1 "n")
print;
a=1;
for (i=0; i<10; i++)
NF, RS
str sprintf("%i", n)
while (1)

SED s/origin/substitution/g; s/a/b/g
tr -d '[:blank:]'
grep -E|-P, sort, uniq
[] || &&, |, >, >>
<<END
heredoc
END
head tail
head -n|-c
tail -c +N

cmd=`printf "str"`
$cmd


BasicBlock, CFG, CallGraph, SSA
AST,GENERIC,HL GIMPLE, LL GIMPLE, SSA GIMPLE, RTL, instruction scheduling, register allocation, coloring, spilling, peephole, pipeline
输入/输出、存储、运算、控制
nested function
(!partial)full parser
source map

.text .data .bss .rodata .symtab

call set use clobber return
对称(symmetric)、交换(commutative)

reg, subreg, mem, cc0, pc, scratch

asmos, sched, vector, call, emutls, c, cxx, option_hooks
🤔可悲不进步的 duangsuse 总是想弄一门自己的程序设计语言。
可不管他怎么写代码,连一个有函数和局部作用域的计算器都弄不出来。

于是他又准备设计一门……

这个计算器是Lambda calculus的计算器。
所谓的Lambda演算就是说,词法作用域(Lexical scoping),不过我还给它加上了 Haskell 一样的 Currying。
Lambda 就是 \formals. body abstraction
不过 currying 的 lambda 只能有一个参数,\formals 需要foldRight才行。
然后可以 apply: substitute + reduce
这次我不用解析组合子了(这是看项目而定,何况现在我已经写过很多,暂时没找到好的架构),手写基于 Feed 的递归下降解析器。

中缀链的解析算法选用普通的左折叠栈式。
一时间不打算支持自定义infix operator,因为我的trie树还没写对一个。
计算器是弱类型的。


下面的语法规则是这种格式:

名字 定义
——
也可能是

名字
定义
——
终结符(一个字符)的名字是小写
非终结符(一个子语法)的名字都是大写
但是 newline, whitespace 可以不大写

a b c 这是按顺序读这三项
为了表示上的方便,我们默认这三项里都可以有空格也即 a b c = a ws b ws c
  ws = {whitespace}?
然后 . 出现的地方不得自动加 ws

a | b | c
是读一项可能是a,b,c之一
{a} 是重复读a
(a)
是结合group的标记,无实际含义
a~t 是重复读取 a,直到 t 成立的意思 (不是 do while…… 只要t成立一遍都不会解析的)
a!t 是读取a,但 t 必须不成立才算的意思

anychar 是任何字符的意思
keyword 除了用来引用终结符,如果引用到的名字不存在则是表示读一"keyword"
然后,a? 表示a可能存在也可能没有

字符的表示基本和Kotlin一样,'a', \t(\的形式不必加'')
字符串也差不多
[] 和正则表达式差不多,不过支持 [ab(rule)] 这种格式
所谓的差不多就是 [123], [0-9a-z] 都支持这种

现在是语法规则
whitespace [ \t\n\r] | Comment
newline CRLF|lineFeed
CRLF "\r\n"
lineFeed '\n'

Comment "{-" (Comment|anychar) ~"-}"

File
{ Def|Expr.}
Def
def Name = Expr
|def Name Abstract
Expr
Let | Abstract | Apply
|If | InfixChain | Atom
Let
let Binding in Expr
Binding Bind { , Bind.}
Bind
Name = Expr

Abstract {— Reduce right —}
lambda LexicalScoped
LexicalScoped
Name LexicalScoped {— one substitution —}
|There Expr {— body with substitutions —}
There "->"
lambda bslash

Apply {— Reduce left —}
Expr Expr | Apply Expr

If
if Expr then Expr else Expr
InfixChain
infixChain(||; &&; ==,!=; <,>,<=,>=; +,-; *,/,%; **;)
Atom
Group | Unary | Name | Literal
Group '(' Expr ')'
Unary UnaryOps Atom
UnaryOps unary(!, -)
Name {— Single _ is reserved —}
(_ | [A-Za-z一-鿕]).{[_A-Za-z0-9一-鿕]}?
|`anychar~newline`
Literal
Integral | Rational | Boolean | Char

hexDigit [0-9a-fA-F]
NumpartP(digit)
digit | {digit _?} digit
Numpart NumpartP([0-9])
sign '+'|'-'

Integral
sign? . ("0b".NumpartP([0-1])
|"0x".NumpartP(hexDigit)
|[1-9].Numpart
|[0-9]).[lL]?
Rational
sign? . Numpart.(dot Numpart).([eE] . sign? . Numpart)?.[fF]?
Boolean
true | false
Char quote.(
anychar![(quote)(bslash)(newline)]
| EscapeSeq).quote
EscapeSeq
bslash.(UnicodeLiteral | Escape)
UnicodeLiteral
u . hexDigit.hexDigit.hexDigit.hexDigit
Escape
[tbnr(quote)(dqoute)(bslash)$]

dot '.'
quote '\''
dqoute '"'
bslash '\\'
我去看看 Kotlin 好像已经被绝大部分 Android 开发者采用了,真是良币驱逐劣币,可怜的 Jawa。

其实Kotlin细节上的实现难度还挺多的,比如 fun <E> E?when (val a = 1) 这种语法糖或者类型推导的
我这种描述式没入门是不可以的
就语言的实现而言,Kotlin显然不是入门选项
Forwarded from dnaugsuz
typealias PredicateOn<T> = T.() -> Boolean
typealias Producer<R> = R
fun <R> retry(n: Int, terminate: PredicateOn<T> = { true }, op: Producer<R?>): R? {
for (_i in 1..n) {
val res = op() ?: return null
if (terminate(res)) return res
}
return null
}

这么写岂不是也可以……
骚操作一点(不建议)甚至可以这么写
fun <R> retry(n: Int, terminate: PredicateOn<T> = { true }, op: Producer<R?>): R? {
for (_i in 1..n) {
val res = op() ?: return null
res.takeIf(terminate)?.let { return it }
}
return null
}

写成Java一样意义不明的风格是哪般……
真鼓吹数学的人都去学抽象代数机器证明了,次一点的也搞范畴论Monad学descriptive甚至逻辑式去了,应用编程就写好看点,为什么起名字喜欢起数学糟粕形式的名字……
难道还真应验了王某人的那句话『你越是看不懂越觉得自己智商低、越觉得我牛逼』……

也可以 functional inline
加个 inline 就行,然后如果报错就继续加 crossinline……