Forwarded from Airsaid
implementation 是 runtime,那么 runtimeOnly 又是?
Forwarded from Fei Yang
@AntiRevoke
請幫忙檢舉謝謝(
Report > Other
範文:
請幫忙檢舉謝謝(
Report > Other
範文:
This channel provides a "plugin" for tdesktop that breaks the delete message feature for other chat members, this plugin violates clause 1.4 of telegram's api tos, please ban this channel.借着这个官方手刃同人的机会,咱来谈一谈 Channel comment board 应该怎么写。
这里不提及回调、消息队列、按钮盘和内联之类的细节,只写成接受必要参数的 fun onXXX() 的形式
与 Telegram 的数据交流与存储责任优先提及:
inline keyboard 各钮的文本和 callback ID 由tg保存,回调含 targetMessage
bot PM(private message) 含事件 onMessageEdited, onMessageDeleted
单单实现添加评论很简单,在按钮链至PM /start 后提示用户输入,再更新目标消息、插入"${user.name}: ${msg.text}"即可。
不过这个流程会被打断成 inline-button 存 targetMessage 再 pm 得检查关于 user 的 state (1参, targetBoard) 才能做到收到后更新。
这个状态表优化后就是 Map<UID, MID>
可以设计为 UserState: add(u,v) get(u) pop(u) 的形式
如果要支持编辑/删除消息操作,必须进行一定程度的关系型数据库建模。
因为文本是由 board 保存的,可以仅对 board msgId : PM msgId 实际储存,从而能在 PM 删除时 getBoardMsg
Board(channelId, msgId)
hasMany PM(msgId)
顺便存 chan. Id 也无所谓,如果实现 channel 的 board 枚举用得到
至于编辑可以实现 parse:(String) -> Map<UID, String> 操作和对应的 toBoardText() 操作,当然也可以直接 String.modifyBoardText(i, text)
以字符串保存列表必须处理转义问题(比如单项的换行符必须保留,人类可读,就可以用 "\n(.*): " 切分而替换单项的文本,不过在 tg 里用 bold mark 标注用户名就可以了),但这样还是比独立存储文本再去拼合的开销低。
但仅这样还差一点:不知道要修改的是第几条。假设一个 board 同 user 只能有一条评论,可以再建立一个记录 Board hasMany BoardUser(no, user) ,或者如果 SQL 扩展支持数组的话,直接保存用户ID数组
必须保存创建编号来升序排列,而可 indexOf 查出编辑消息用户的位置,不过这样也就可以同时做一个『最近评论』页了…… (以编号降序,某人在某板评论了 board.findPM(/**/) )
毕竟关系数型据库的 record 除了 "relation" 外也称为 "entity"
当然,更正经的做法是直接保留 PM 的创建顺序,然后查某pm在某board里的位置(pm.board/*findBoard()!!*/.indexOf(pm)),上面是提示思维过程。
关系型数据库的名字可不是白叫的,它不是像 CSV 一样,仅仅像 ORM(object rel. mapping) 一样是 List<T> ,尽管它所支持的“关系”非常初步,而且基于 foreign key,只有 hasOne/hasMany 以及 relation "wtf" 的双边关系。
这里不提及回调、消息队列、按钮盘和内联之类的细节,只写成接受必要参数的 fun onXXX() 的形式
与 Telegram 的数据交流与存储责任优先提及:
inline keyboard 各钮的文本和 callback ID 由tg保存,回调含 targetMessage
bot PM(private message) 含事件 onMessageEdited, onMessageDeleted
单单实现添加评论很简单,在按钮链至PM /start 后提示用户输入,再更新目标消息、插入"${user.name}: ${msg.text}"即可。
不过这个流程会被打断成 inline-button 存 targetMessage 再 pm 得检查关于 user 的 state (1参, targetBoard) 才能做到收到后更新。
这个状态表优化后就是 Map<UID, MID>
可以设计为 UserState: add(u,v) get(u) pop(u) 的形式
onKeyboardCallback(msg,key) = state.add(msg.user, msg)
onMessage(chat,msg) if (chat.isPM)
msg.command == "start" -> if (state.get(msg.user) != null) /*提示*/
state.pop(msg.user)?.let { /*更新board*/ }
如果要支持编辑/删除消息操作,必须进行一定程度的关系型数据库建模。
因为文本是由 board 保存的,可以仅对 board msgId : PM msgId 实际储存,从而能在 PM 删除时 getBoardMsg
Board(channelId, msgId)
hasMany PM(msgId)
顺便存 chan. Id 也无所谓,如果实现 channel 的 board 枚举用得到
至于编辑可以实现 parse:(String) -> Map<UID, String> 操作和对应的 toBoardText() 操作,当然也可以直接 String.modifyBoardText(i, text)
以字符串保存列表必须处理转义问题(比如单项的换行符必须保留,人类可读,就可以用 "\n(.*): " 切分而替换单项的文本,不过在 tg 里用 bold mark 标注用户名就可以了),但这样还是比独立存储文本再去拼合的开销低。
但仅这样还差一点:不知道要修改的是第几条。假设一个 board 同 user 只能有一条评论,可以再建立一个记录 Board hasMany BoardUser(no, user) ,或者如果 SQL 扩展支持数组的话,直接保存用户ID数组
必须保存创建编号来升序排列,而可 indexOf 查出编辑消息用户的位置,不过这样也就可以同时做一个『最近评论』页了…… (以编号降序,某人在某板评论了 board.findPM(/**/) )
毕竟关系数型据库的 record 除了 "relation" 外也称为 "entity"
当然,更正经的做法是直接保留 PM 的创建顺序,然后查某pm在某board里的位置(pm.board/*findBoard()!!*/.indexOf(pm)),上面是提示思维过程。
关系型数据库的名字可不是白叫的,它不是像 CSV 一样,仅仅像 ORM(object rel. mapping) 一样是 List<T> ,尽管它所支持的“关系”非常初步,而且基于 foreign key,只有 hasOne/hasMany 以及 relation "wtf" 的双边关系。
今天早上胡思乱想了一会,给一个写起来节约空间,基本上算英文绝句初版的 AtScript (为啥东西设计的现在提了也没用) 弄了个有意思的缩进语法:
这个英文版的结构是 class/thing/insta/fun 用 were, for/while/if/when 用 do , 闭包用 do |a,b| 。
这个利用分号的语法也是为了节约击键次数(为此里面的类型都是 Bool,IntX+Idx+Cnt,Char,Str 这样)设计的特殊调用参数列表语法,有了它应该还可以结合 optional 参数,拿来写 DOM:
实现什么的不用担心啦,就是在 o.x, o[i] 和 o() 左递归链后面加料(:) 呢。
说起来,如果 o() 不在左递归链里,而是把 o.op() 解析为 GiveSelf(o, Call("op", [])) 也是可以的,但是和底层不太对仗也容易搞混优先级,不过优点是可以写出 o.!contains(x) 这种基于函数变换的表达式(就有点像 Elixir 的 |> railway 了),哈哈。
不过重点不是这个。我打算给这么语言支持 suspend function (也就是 coroutine)
实现起来并不困难,扩充于 FunctionAst 建立一个 CoFunctionAst 就好了,里面嵌套的 CoFunc.invoke 也靠 instanceof 判断能提供 指令指针栈的 resume 信息, CascadeMap+LexicalBinding 就能保留闭包数据,可惜只能做到 Python/ES6 的语句级别保留执行状态。
其实我对 coroutine 是不了解的,除了知道 Lua 是非对称协程(只能将执行权转交给 resume 者的协程)、 ES6 的 await/async 和 co 的 Promise/Thunk(返回“收回调”函数的函数) 是由将 suspended 协程(下片也即其“回调”部分)交给其之前 yield 的 Promise 的方式来解决回调嵌套外,不知道具体的利用方法(如序列化、 "suspend fun" 的封装)。
为此我去问同写 Kotlin 的冰封哥,Kotlin 的协程为什么会有"Scope",答复是“CoroutineScope 是 CPS 变换的 Context” (CPS, continuation passing style, 传递函数进程的手段),我一直没弄懂这个上下文到底是咋用的,它和 Scoping 又有没有关系。
CPS 可理解为上面 ES6 await/async 二者一起(await=yield, async=co) 进行 await op1(); op2() 变执行实为 op1(() => op2()) 的手段
我不解的是,如果 continuation 是传递回,那必须 capture 住整个栈,但传递上是不需要的。
如果 Kotlin 的 CPS 就是把 o.await() 前的部分交给 o ,复苏 continuation 就仅需 return 到调用栈某一层因为栈上已经保留了所需信息,为什么会需要 CoroutineIntrinsics 的 create,resume,suspendOrReturn 三基元呢?
这种方法能实现 Sequence(即 generator) ,看起来它比协程高级,那么它到底和被数据化的子程序状态(coroutine)有什么关系?
百思不得其解,于是我打算以我懂的 ES6 generator 来实现(缺点是只能把 yield 建模为语句而不是函数)
但是我仍想用三基元,而且还是想让 yield 函数去带参 suspend 当前协程。
结果我发现了一个问题,导致我有点理解了 Kotlin 的设计:协程挂起后该由谁恢复?
suspend fun s123 were
yield(1); yield(2); yield(3)
(老实说 #Kotlin 的“无需分号化”也有点迷, println(1) println (2) 算不算中缀调用说不清)
上例 s123() 挂起了可以得到当前项,最后可以抛 StopIteration 之类(或作为 resume() 返回值),可是假设我是要实现 Iterator 而必须有 next/hasNext ,从而我得保留 1项的流不变视口,在语言内部自然是不适合处理(为扩展性)
于是我想到了 fun sequence(builder: suspend BuilderScope.() -> T) 收的函数类型,其实有 BuilderScope.yield
这样你可以把 sequence builder 直接表达为 Iterator :
明白了,那么 delay(1000).await() 也就可以理解为 Scope 里的 ext fun Async/*Deferred*/<Unit>.await() ,这也就解释了 Kotlin 支持 local fun 却不支持其 with receiver 是因为仅 class 级别可以。
它和协程对象本身的关系就是:(制定一个顺序,这里举例回调)
结合星野大佬的经验 http://blog.hoshino9.org/2018/12/31/paint-board.html :
据说 runBlocking 会在所有内部 coroutine 执行后返回,所以此程序在 timer= 时阻塞,要改正只需换回 GlobalScope.async 。
await 本身也算协程,感觉应该很奇怪,但这是必须的。
假设没有任何 CPS 编译优化, op.await() 就应该是把当前上下文(协程状态)交给 op 以待其 resume ,所以 await 当然是非阻塞的,而且它会将当前协程挂起 (suspend fun)
thing WTF were
fun init() = noOp()
val layout = verticalLayout:
text("emmm")
button()
这个英文版的结构是 class/thing/insta/fun 用 were, for/while/if/when 用 do , 闭包用 do |a,b| 。
这个利用分号的语法也是为了节约击键次数(为此里面的类型都是 Bool,IntX+Idx+Cnt,Char,Str 这样)设计的特殊调用参数列表语法,有了它应该还可以结合 optional 参数,拿来写 DOM:
import markup.html.*
root = body:
script(src="wtf.js")
div(css="list"):
a("#", "link")
print(Document:
head(title("bad"))
root)
实现什么的不用担心啦,就是在 o.x, o[i] 和 o() 左递归链后面加料(:) 呢。
说起来,如果 o() 不在左递归链里,而是把 o.op() 解析为 GiveSelf(o, Call("op", [])) 也是可以的,但是和底层不太对仗也容易搞混优先级,不过优点是可以写出 o.!contains(x) 这种基于函数变换的表达式(就有点像 Elixir 的 |> railway 了),哈哈。
不过重点不是这个。我打算给这么语言支持 suspend function (也就是 coroutine)
实现起来并不困难,扩充于 FunctionAst 建立一个 CoFunctionAst 就好了,里面嵌套的 CoFunc.invoke 也靠 instanceof 判断能提供 指令指针栈的 resume 信息, CascadeMap+LexicalBinding 就能保留闭包数据,可惜只能做到 Python/ES6 的语句级别保留执行状态。
其实我对 coroutine 是不了解的,除了知道 Lua 是非对称协程(只能将执行权转交给 resume 者的协程)、 ES6 的 await/async 和 co 的 Promise/Thunk(返回“收回调”函数的函数) 是由将 suspended 协程(下片也即其“回调”部分)交给其之前 yield 的 Promise 的方式来解决回调嵌套外,不知道具体的利用方法(如序列化、 "suspend fun" 的封装)。
为此我去问同写 Kotlin 的冰封哥,Kotlin 的协程为什么会有"Scope",答复是“CoroutineScope 是 CPS 变换的 Context” (CPS, continuation passing style, 传递函数进程的手段),我一直没弄懂这个上下文到底是咋用的,它和 Scoping 又有没有关系。
CPS 可理解为上面 ES6 await/async 二者一起(await=yield, async=co) 进行 await op1(); op2() 变执行实为 op1(() => op2()) 的手段
我不解的是,如果 continuation 是传递回,那必须 capture 住整个栈,但传递上是不需要的。
如果 Kotlin 的 CPS 就是把 o.await() 前的部分交给 o ,复苏 continuation 就仅需 return 到调用栈某一层因为栈上已经保留了所需信息,为什么会需要 CoroutineIntrinsics 的 create,resume,suspendOrReturn 三基元呢?
这种方法能实现 Sequence(即 generator) ,看起来它比协程高级,那么它到底和被数据化的子程序状态(coroutine)有什么关系?
百思不得其解,于是我打算以我懂的 ES6 generator 来实现(缺点是只能把 yield 建模为语句而不是函数)
但是我仍想用三基元,而且还是想让 yield 函数去带参 suspend 当前协程。
结果我发现了一个问题,导致我有点理解了 Kotlin 的设计:协程挂起后该由谁恢复?
suspend fun s123 were
yield(1); yield(2); yield(3)
(老实说 #Kotlin 的“无需分号化”也有点迷, println(1) println (2) 算不算中缀调用说不清)
上例 s123() 挂起了可以得到当前项,最后可以抛 StopIteration 之类(或作为 resume() 返回值),可是假设我是要实现 Iterator 而必须有 next/hasNext ,从而我得保留 1项的流不变视口,在语言内部自然是不适合处理(为扩展性)
于是我想到了 fun sequence(builder: suspend BuilderScope.() -> T) 收的函数类型,其实有 BuilderScope.yield
这样你可以把 sequence builder 直接表达为 Iterator :
var lastItem: T? = runCatching { resume(builder) }.getOrNull()
// 只是举个例子, T:Any? 也可独立出 var hasLast
fun hasNext() = lastItem != null
fun next() = lastItem.also { /**/ }
明白了,那么 delay(1000).await() 也就可以理解为 Scope 里的 ext fun Async/*Deferred*/<Unit>.await() ,这也就解释了 Kotlin 支持 local fun 却不支持其 with receiver 是因为仅 class 级别可以。
它和协程对象本身的关系就是:(制定一个顺序,这里举例回调)
runOp(callback={ resume(this@Scope) })结合星野大佬的经验 http://blog.hoshino9.org/2018/12/31/paint-board.html :
var timer = GlobalScope.async { delay(1000) }
fun main() = runBlocking {
println("begin")
timer.await()
timer = async { delay(3000) }
println("finshed")
}
据说 runBlocking 会在所有内部 coroutine 执行后返回,所以此程序在 timer= 时阻塞,要改正只需换回 GlobalScope.async 。
await 本身也算协程,感觉应该很奇怪,但这是必须的。
假设没有任何 CPS 编译优化, op.await() 就应该是把当前上下文(协程状态)交给 op 以待其 resume ,所以 await 当然是非阻塞的,而且它会将当前协程挂起 (suspend fun)
blog.hoshino9.org
临终之日, 新年之时
最后一天今天就是这一年的最后一天了与此同时, 你谷 也迎来了冬日绘板活动也因此, 各类脚本层出不穷不过说到底, 绘板的竞争还是脚本的竞争是 Cookie 数量的竞争
Forwarded from BLUG Username Hold
请各位订阅者如有需要,左转到主站 https://beijinglug.club 和聊天室。谢谢茄子~
Forwarded from 螺莉莉的黑板报
Forwarded from 螺莉莉的黑板报
https://www.bilibili.com/video/BV1Y54y1D7cT
当吴松磊说「有一点点难」的时候,你就要小心了
当吴松磊说「有一点点难」的时候,你就要小心了
Bilibili
【回形针PaperClip】 二维码的秘密_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
你扫描二维码的一瞬间究竟发生了什么?为什么二维码被破坏了也能扫出来?
是啊, 23+2 mod 24 = 1 位置记数法进制问题的确很基础,然后乘法表什么的的确扯,就是
(1..9)./*flat*/map { a -> (1..9).map { b -> if (b>a)/*(1*9==9*1)*/ "" else "$a×$b = ${a*b}"} } 嘛,不稀奇呢