/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
记录一种思维方式:

刚才在回答 @Zhai2333 大佬的问题时我提到了树(Trees)

我说(伪jzm 🐸

但是我想,我见到你们这样热情啊,一句话不说也不好。所以你刚才你一定要——在宣传上将来如果你们报道上有偏差,你们要负责。我没有说这很简单(逆向 JavaScript),没有任何这个意思。但是你问……你一定要觉得要问我……对这类代码保护措施有没有方法。我能不能写 AST 模式识别重构器?AST 处理是编译原理优化编译入门技能,我怎么能不会?
...
你们毕竟还 too young(太年轻),明白这意思吧。我告诉你们我是身入树状图了,见得多了!啊,OI 入门的哪一个算法我没讲过?码农他们——你……你们要知道,美国的 @ice1000 ,那比你们不知道高到哪里去了。啊,我跟他谈笑风生!所以说编程啊,要……还是要提高自己的知识水平!懂我的意思——识得唔识得啊?(懂不懂啊?)

(逃跑,,,我很菜的,不过希望有点幽默的说

我提到了树和 OI,这不禁使我想到了之前看 OI 入门书的二叉树,然后我就不禁考虑到了一个问题:完全二叉树(除了最后一层 leaf 外、每一层都有两个子节点)如果层数是 n 层,那么一共有多少个节点?(弄错问题了... 是第 n 层有多少节点、那个除了递归或者 sum 外,或者手动试着代数化简、我没办法)

本来是很 immediate 的内容(发答案了,就是 (n-1)**2 + 1)
n-1 是因为第 0 层很特殊、 +1 是补回第 0 层

我却想了一会(虽然开始我隐约有正确表达式的直觉,虽然只是一个伸展的树形图样,然后两层之间存在某种运算连接起来的那样)而且还体会到了之前完全不懂数学的恐惧... 😨

现在我得到了答案(莫名其妙就又想到了,噢,原来不每层就是前面的 n-1 层 *2 么)(我的递归素质就有这么差....)

同时又得到了两个思考方法:

1. 考虑递归程序的时候,把每层看成是自己想要的数据。
比如上面的算层数、每个节点就是一个『1』
这样你就能有
root = 1 + bin
bin = bin + 1 + bin
这种图的直觉了,然而光有它还不够,你要能看 (1 + 1) | (1 + 1) 换得成什么...
给我一种感觉 好像要反过去回溯的时候 才能感受到这种可能...

2. 考虑递归程序的时候,只看一层不够就看两层

bin0 = bin1 + 1 + bin1
bin1 = bin2 + 1 + bin2
....
bin2 = 1

3. 可视化数学计算,这样你就可以把数据结构和数学式子一起对称着看了

比如,要有把乘方看成树形的能力:
2**3=
(2*2)+2
/ \
2 2

4. 最后上面的问题我是怎么解决的,

首先,我不知道为什么就没有看根节点...

然后,每一层都有 2 个子树、直到 (n-1) 层(最后一层没有子树只有叶子,要不然你也不能非惰性地构造 infinity data structure)

本来我开始没有想出来的原因是我觉得这是递归的,没法直接算...(其实也是可以的)(废话)

后来发现,其实要求第 n 层(第 0 层就是 1),只需算 n**2 即可(每层都叉一次 *2、叉了这么多次,有这么多个 1)
...

唉,现在就只有这点水平

不过你看完后就发现,其实“数学”和编程从本质上看都是没有差别的,解析数学、微积分什么的也是属于数学的 buff,但都是很『基础』的东西
This media is not supported in your browser
VIEW IN TELEGRAM
日,数学... 为什么变化起来就有那么多特例
难学啊,排除计算也一样....
回来的时候我考虑了一下那个 C 莫名其妙的多维度数组的实现,以及为什么我平时用 y-first scanning

y-first 的意思就是说,当我扫描二维矩阵的时候,我会用 matr[y][x] 这种索引方式
因为一般数据都是从左到右扫描输入的,这样的话,按折行(下一个 y)切分会好写一些,不需要去每个去专门索引 matr[x][(0..len]]

前者的图示看起来像是这样:
int matr[y=6][x=4]
x
3 0 0 0 0 0 0
2 0 0 0 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 0 0
+ 0 1 2 3 4 5 y

当我们需要 ((int[6][4]) matr)[1] 的时候,得到 (matr + 4*1) 的位置
得到了
2: 0 0 0 0 0

int matr[x=4][y=6]

y
5 0 0 0 0
4 0 0 0 0
3 0 0 0 0
2 0 0 0 0
1 0 0 0 0
0 0 0 0 0
+ 0 1 2 3 x

它看起来像是这个样子

不过这很 naive:因为它只是幼稚的数据描述策略问题而已,还有一个不那么 naive 的:映射到一个一维数组,怎么递归去计算这个 a[n][m] 的索引呢?

你以为这是一个『n 维数组』,实际上它是一种对存储空间的描述,实际上内存是连续的,对于这种『每个维度长度都不同』的该怎么办呢?

方法就是类似上面的计算。
C 的数组给人不符合直觉的感觉,和指针、const modifier 什么的一样,很不对称...
我真的不知道这些和 typenames 有啥不一样的地方,为什么他们就是用一种不同的方式来描述

char * 这个类型是 char 的指针
char 这个类型是 char * 的指针

const char[] 是 const char 的数组
(C++) char &a[] 是 char 引用... 的数组
char (&a)[] 是引用数组 char[]

最后,
char*
是 char 的指针可是 char[n][m] 是代表一个多维数组,可是这个数组呢?
如果看作是数组的数组,实际上它是 长度 n 关于 char[m] 的数组
听起来很正常,问题是 (char[n])[m] 看起来怎么都类似长度 m 元素 char[n] 的数组... 就很奇怪

我...

其实这么倒着放还可能是有原因的,因为怎么看好像区分一维数组和多维数组是一个蛮正常的思路,数组的数组才不应该存在
可是对编译器就有这么一个问题:怎么分配它、怎么拿到元素的指针

分配数组的数组很简单,看看这个 Haskell 程序:

module Dim where

type Size = Word
type Dims = [Size]

allocSize :: Dims -> Size
allocSize [] = 1
allocSize (l:ss) = l * allocSize ss

这个『神奇』的递归程序是做什么?就是 items * size 而已,而 item 的 size 就是下一层的大小,如果没有了实际上还得在叠加一层,这时候用 (*) 乘法的透明操作数 1 即可

当然,allocSize <=> foldl (*) 1 <=> product ...

allocSize [1,2,3] = 1 * 2 * 3 *1 = 6,所以说 array 是 homogenus product type。

那么因为乘法是有交换律的,所以在两种数组上分配大小计算方式都有效。
再来看看索引的计算

getElemPtr :: Dims -> Dims -> Size

现在你有维度们的长度,给你索引们,请问:这个元素存在哪个位置?

对于递归的数组,还是比较简单的
思量一下,算 [1][3],首先我们有一个 [1] 的大小,然后乘索引 [3] 即可

getElemPtr [] [] = 0
getElemPtr (d:ds) (i:is) = (getElemPtr ds is) + (d*i)

getElemPtr [1,3] [0,1] = 6
getElemPtr [1,3] [0,2] = 9

这样就好了,欸,好像是错的吧... 总之就是和 C 的弄混了... 算
其实本身没有错(迫真),我的例子错了...

其实这个的确写对了,就是递归求基索引(idx*dim),再加上自己的索引而已,问题在于 size 没有得到显式地体现(迫真

比如有 (a[2])[10],(a[0])[1] 就是 1、(a[1])[0] 就是 10

这算是递归入门... 至于那个 C 的多 dimen 数组,倒过来算就可以了,做出来就行...
/tmp/duangsuse.sock
啊,那个我没有考虑到,其实... 写的插件还可以讲一下,所以前端给 #HTML #JavaScript 之前因为 Fx 阅读模式里面 link anchor 有 underline(decoration) 所以想加去这个的 CSS,后来才知道本来就没有... 如果有的话,可以 a { text-decoration: none; } 接下来简要说说几个小辅助插件了 首先是 NSFW Template,这使用到了 HTML5 的新 <template> tag bound 本来确实可以利用 prope…
那我也就只好快速地讲一下这七个插件了,发了文我还有很多事...

首先是
== NSFW template,暴露主要函数 showTemplate(attr, finit)、辅助函数 selectDelete(cs), addCSSClass(name) 就 OK 了

function showTemplate(attr, finit = doNothing) {
let templates = cssSelect(templateHasAtt(attr));
foreach(templates) (function(it) {
let into = merge(it.content);
finitize(into, finit);
prepend(finit, into);
});
}

selectDelete = cs => cs.lets(foreach) ( _.delete );
addCSSClass = name => nd => nd.classList.add(name);

这个插件就是去添加一些可选显示的内容,包裹在 <template attr> 标签里

== Abbr view

这个逻辑比较简单,类似 NSFW template。因为在一些设备上不能使用 "hover" 查看 abbrev... 只好在点击时在后面插入内 abbr 的实际容了。
写入的时候先新建一个 attribute,用于记录 abbr 已经被展开,每次 switch 的时候判断一下 shown => hide、hidden => show

暴露主要函数 hookAbbr(nd) 就可以了

cssSelect('abbr').lets(foreach).lets(hookAbbr);

逻辑也很简单,就是设置 onclick,二元状态机,在自己之后展开

function _hookAbbr(nd) {
return () => { if (!getAttr(nd, 'shown')) {
insertAfter(nd, makeTextTag(nd.title)); setAttr(nd, 'shown');
} else {
nd.nextSibling.delete();
} };
}
function hookAbbr(nd) { nd.onclick = _hookAbbr(nd); }

什么的
...我多么希望快速的讲完啊,可是又讲的很细,现在很晚了...

说功能和要点算了。

Night 的要点就是:提供文档阅读视图的用户风格选项

首先它自动根据当前时间,切换默认 Night/Day,其次,它支持:

+ 配色风格:Day/Night/Old
+ 字体:有无衬线
+ 字号:大小调整
+ 容器宽度:大小调整

实现:提供一个 autoDayNight() 导出逻辑来实现自动配色,没有其他要点。

Reflink preview 的要点

按照 invisible dt 提供的元数据,给指定的 anchor 标记(需要使用 id 来指定)挂上钩子,在 iframe float 里弄出来个(可以 close 的)内容,并且提供原本内容的链接

Music player 的要点:对 WebAudio 的一个简单前端封装,不支持播放队列什么的,只能全局放一个(动态 WebAudio)
可以调整音量、pos 和播放/暂停,支持画 WebAudio 的 Spectrum Canvas 图

本身暴露一个 playAudio(url) 的 API,使用 XHR 流即可

Footnote Xref 的要点

在某个 section 下面(扫描直到下一个 h*)
扫描所有的 subscript 区段起始的 footnote 元素,

接下来利用 class .fn 查找内容的 footnotes(foreach),
按照 subscript 对应到实际的 footnotes (自己动态建立 id,a href 到对应 footnotes,同时 footnotes 也建立 a href 到自己的动态 id)

foreach cssSelect('.fn') {
let footnote = footnotes[fnid(it)]
let [fid, rid] = makeId.times(2);
let fa = makeAnchor(footnote, fid);
let ma = makeAnchor(it, rid);
drawTo(fa, rid);
drawTo(ma, fid);
}

重要的是生成双向引用需要同时拿到两个引用

最后 Contents Tree 的要点是 DOM Tree recursive pattern destruct

subsec(root)

这个函数构造 <h1> - <h5> 的列表,
从 root 开始枚举它的 nextSibling,

如果不是 header tag 则跳过
如果是同级别 header,加入
如果是低级别 header,递归扫描,加入
如果是高级别 header,结束扫描

阅读时间的要点

就是提供字数统计(只需要算 length 即可,大概的)、行数统计、引用 链接 和代码统计、header 统计
本身虽然可以做比较好的预估(比如说,pattern matching)
可是不大算这一点,只需要算好后写 min 、字数行数拿 , 3 位隔一位就可以了,点击以显示详情
关于 Curry 函数

Curry 是什么呢?本来 curry 的意思是 Lambda composition ( f.g = \args -> f (g args) ) 很难去接受一些『多参数函数』(要不然处理起来就很迷人...)
于是 Lambda calculus 有个 currying: \x y. x = \x. \y. x (原本一个多参数的 lambda 现在变成了多个单参数 lambda 的组合)

这样就有一个好,因为 lambda 抽象(abstraction) 的 variable substraction 可以给一些项目提供参数,而未必要立刻『实际执行』这个函数:

add = \a. \b. (a + b)
add2 = add 2 = \b. (2 + b)
add2 1 = 3

它可以提供『不能重写』的参数默认值(因为那里 2 就是立即值或者 UpValue 了,递归的时候这个东西不是参数的)

可是很多函数式编程语言,比如 Haskell 是这个样子,JavaScript 就不是这个样子。

不过有 Function.prototype(参见我之前写的 LuaOOP 原型面向对象继承实现).bind
可以给指定默认参数

不过,指定就最好得一次指定完,不然很麻烦(因为 this 要传来传去的... 而且你还得手写 curry 参数的调用)

我希望这样的 curry:

var puts = bound(matrix, 'putXY').curry()
var puts00 = puts(0)(0)
puts00('0,0')

然后我早上赖床(逃跑)的时候就在想,该怎么实现这个多参数 curry 呢?

开始我很 naive 地想到,好像这是在针对 accumlator(计数器一样的东西,总之就是不断被『从自己构造』)
去操作,于是非常自然地想到了 foldl, foldr (其实 foldr 的确是可以的,而且 compose = foldr (.) id,不过这里不提右递归的方法)

可是我又想到,这显然是不行的。curry1 不管怎么样至少是接受一个参数返回接剩下参数的... 这样的话毫无意义,
因为我实际上一直在提供第一个参数。

然后我就想到了,既然是要构造这么一个递归的情况(第一次填 0、每次填第 n+1 个参数)
为什么不先构造 curry 最后一个参数的情况,然后串起来呢?这样不就可以了?
不过这当然是没有那么简单的,因为 bind 是 left-to-right,然后手动调用也得拿到每一个 curry 的参数
不过我们可以用 effect. 创建的时候弄一个 array 每层去 push 一下就好了

算了还是右递归 bind 吧(当然自己写也可以,就是给左边填一个参数返回右边剩下的)... 用 effect 没必要

function _curryN(f, ff, n) {
if (n == 0) return ff;
return function nextDefault(x_)
{ return _curryN(f, ff.bind(f, x_), n-1); };
}

Function.prototype.curryN(n) { return _curryN(this, this, n); }

总之递归构造数据还是... 应该是符合直觉好 吧...

#JavaScript #FP #Haskell
/tmp/duangsuse.sock
...我多么希望快速的讲完啊,可是又讲的很细,现在很晚了... 说功能和要点算了。 Night 的要点就是:提供文档阅读视图的用户风格选项 首先它自动根据当前时间,切换默认 Night/Day,其次,它支持: + 配色风格:Day/Night/Old + 字体:有无衬线 + 字号:大小调整 + 容器宽度:大小调整 实现:提供一个 autoDayNight() 导出逻辑来实现自动配色,没有其他要点。 Reflink preview 的要点 按照 invisible dt 提供的元数据,给指定的…
最后那个就是非常简单的递归数据构造逻辑,最后的结束扫描只是因为我们觉得『出现比它大的 heading 代表它结束了』而已,如果知道 ending 的话当然应该提早返回

构造出的数据非常简单,思考一下为什么递归扫描(此时把子树的 level 看作根文档)

相关知识,Python、Haskell 的缩进语义也是可以通过类似判断实现的,只不过使用 DOM Tree 接口去解析会方便很多
/tmp/duangsuse.sock
啊,那个我没有考虑到,其实... 写的插件还可以讲一下,所以前端给 #HTML #JavaScript 之前因为 Fx 阅读模式里面 link anchor 有 underline(decoration) 所以想加去这个的 CSS,后来才知道本来就没有... 如果有的话,可以 a { text-decoration: none; } 接下来简要说说几个小辅助插件了 首先是 NSFW Template,这使用到了 HTML5 的新 <template> tag bound 本来确实可以利用 prope…
以上的函数库还要加上一些方便的 operator:

forIter 要能够接受 InterruptedException 来支持内部函数去 breakIter() nextIter() 打断/

take / drop / collect = take.curry1(Infinity)
takeWhile / dropWhile
zipWith(f, xs, ys)
map(f, xs)
filter(p, xs)
iterBy(node, docall('get', 'nextSibling'))
ap(sub, [1,2]) 这种

因为是手写就不 AMD/CommonJS 了
还是支持 ES5 算了,眼花的特性,毕竟 ES5 也老高级了...
JavaScript 面向语言编程应该非常简单的说,使用 副作用的流完成 parser combinator...
这样就 好看 可是不... 总感觉有些东西
这个 dropWhile 本来可以讲一个问题的,可是觉得没有必要讲了(就是一个同时持有当前项和 lookAhead 项目的问题,对于 stream 式的差别只在时序、这里只在最后一次迭代)
一个时序问题,修改前的程序会多迭代一次、跳过流里的一项,现在的程序不会了(移动 n!=0 到前面,短路 &&...)
写各种 list operator 写到手软... 还没有开始写业务逻辑...
fp.js
9.3 KB
#FP #JavaScript #Haskell 🤔 绝对要开始写业务逻辑了...
Forwarded from Deleted Account
def makeCats(xs, t); t.times { xs = xs.map { |x| xs.map { |it| it+x }  }.flatten }; return xs; end
Forwarded from Deleted Account
Forwarded from Deleted Account
makeCats('a'..'z', 1)

=> ["aa", "ba", "ca", "da", "ea", "fa", "ga", "ha", "ia", "ja", "ka", "la", "ma", "na", "oa", "pa", "qa", "ra", "sa", "ta", "ua", "va", "wa", "xa", "ya", "za", "ab", "bb", "cb", "db", "eb", "fb", "gb", "hb", "ib", "jb", "kb", "lb", "mb", "nb", "ob", "pb", "qb", "rb", "sb", "tb", "ub", "vb", "wb", "xb", "yb", "zb", "ac", "bc", "cc", "dc", "ec", "fc", "gc", "hc", "ic", "jc", "kc", "lc", "mc", "nc", "oc", "pc", "qc", ...]
Forwarded from Deleted Account
递归下来懒得想了,跑路(不过就是每次往上面一层去 map (\x flatMap ([x] ++)) xs

就可以构造出 a (a) b (a) ... z(a), a(b)... a (aa), z(aa), a(ab)....
Forwarded from Deleted Account
可以(

#define GETC (ch = getchar())
static inline int readInt() {
signed int n = 0;
char ch = '\0';
while (isspace(GETC));
if (ch == '-') { n = ~n; GETC; }
//reads natural part
while (isdigit(GETC))
n = (n*10) + (ch-'0');
return n;
}

类似解析组合子的布局