duangsuse::Echo
717 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 dnaugsuz
iseki 觉得 return 能够和 throw 一样被作为表达式吗 🤔
fun op() { do { println(null ?: continue as Nothing) } while(true) }
我觉得好奇怪啊
Forwarded from iseki
返回Nothing不行吗
Forwarded from dnaugsuz
我觉得不行,这样容易混淆……
我觉得可以提供语法糖,但不能是表达式

我很讨厌 fun op() { do { println(listOf(return, continue, break, throw Exception())) } while(false) } 可以解析甚至执行的情况
Forwarded from dnaugsuz
我还是无法接受 continue 可以被作为参数的 case……
println(continue) 我简直发毛
尽管类型层面我们可以检查出 println 不能被执行
Forwarded from iseki
不能编译啊,你怎么可以println(Nothing)呢
Forwarded from dnaugsuz
我是这样想的,如果没有足够的理由,『控制流』表达式我要有所取舍
比如说,一些能够不作为表达式的,return 什么的就专门提供语法糖
Forwarded from dnaugsuz
这个问题我可以到时候弄出我设计那个语言第一个编译器的时候再找其他人谈谈,
之前我没考虑过 break 什么的类型级别可以是 Noting 这件事……
我之前以为 Kotlin 是不允许这样,但我得慢慢去想,举出实际使用例子来

其实这也不是没好处,好像是可以放在 block(closure) 里面的,不过我也不是很确定。

我打算设计的这门语言叫『绝句』,这里有一个简单的例子:

引记法 绝句.区间.数域 (投、换)
对何<项>皆有
括物(我: 行<项>) 为
私下、尾递归的事 二分查找(你: 项、区: 数域): 引数? 为
量 中针 = 区的中值
判我[中针],
是你,回中针
大你,重写(区=区投末,中针前。) “逗号文法 确保(一行(1、2、3).全是,它 不小 一。)”
“二分查找(你, 区.mapBegin { 中针.dec() })”
小你,重写(区=区换始(中针))
“编译器知道没有其他情况”

记得我当初设计的时候(重写是后来设计的一个特性)重写被弄成了个值是『断止』类型的表达式 🤔

一个细节是,它在类型层面建模了 Kotlin 没建模的 Exceptions,这个建模被称为『无常类型检查』

//!语者 无例之物
//!语者 此即存储
对何<值者>皆有
密封的内联物 无常 为
私下的内联物 断止: 无常<*>()
私下的内联物 决常(量 你: 值者): 无常<值者>() 为
算符的事 此即值() = 你
“大致是这样吧,注意这是编译器的 intrinsics”
比如说,假设有 事 读一行(): 无常<文>

尝试,
量 输入行 取者,读一行()。 “内联类没有『我』分配,无法作为通常值存储”
“或者,你也可以写 量 输入行 = 读一行()作决常”
输出 写 输入行 “编译器知道『输入行』的「推帧单位」和赋值语句的是一个,且这一句能执行必定代表无异常发生,智能转型。”
接迎 文件结束不常成『异事』,异事去写出()。 “『标识符』是绝句的一种文法”
“当然关键字<接迎>后不加空格也可以”
终焉,
“这只是个例子”
Forwarded from dnaugsuz
你这指定的好像是类型上界 <T: Any> capture<T extends "Any">
有时候我觉得类型上、下限好理解些,一个「界」字我觉得断言的不够明显,让人困惑(虽然是通用说法)
Forwarded from dnaugsuz
就是类型检查啊,Java 都是泛型擦除的实现,Kotlin 有强十倍的类型系统你还璇它……

Java 早些时候(1.5的时候才加的泛型)没泛型才这么干,到处瞎转转
现在 Kotlin 有了,你不多看点 Kotlin 最佳实践,还是先重新学学再说吧,Kotlin 不是 JDK stdlib 辣鸡。

而且什么叫做都是,链表也是么
Forwarded from dnaugsuz
我给你解释一下,拿一般的那一套,不说什么类型理论、集合不集合值不值的。

既然你已经知道 PECS(producer-extends, consumer-super) 原则什么的,就不说了。
Java 的泛型通配符是一种类型变量,?extends A 配属 A (或者说『小于A』)的任意类型,?super A 配超 A(或者说『大于A』)的任意类型
类型就是谁兼容谁的问题,CharSequence 兼容 String、Number 兼容 Integer, Long, Float,或者说兼容者是被兼容者的子类型(subtype)。
就是说任何操作 (CharSequence) -> * 都可以被 invoke("string instance")
哪怕是 xs[1], xs[2] 这种操作都一样(他们就是 Kotlin 的 operator fun get(index: Int): T) 嘛


泛型加了个参数,不过这里就出了个问题,比如说,

interface Box<T> {
T get();
<R> R let(Function<T, R> f);
}

这里我们写点使用者角度的代码,
void printNumber(Number num) { out.println(num); }
// Function<Number, Void> printNumber = out::println;
Box<Integer> ba = new ValueBox(1);
ba.let(::printNumber);
// Box<Integer>#let(Function<Integer, R>) is not acceptable for (Function<Number, Void>)

其实我们谈的 Box<T> 就是 Kotlin 的 Box<in T>,因为它的类型参数只在「消费者位置」出现,你说对应 ?super XXX,很正确,但知道不等于理解,所以要再学。

所以大家都这么写:
  <R> R let(Function<? super T, R> f);
然后对 Java8,it checks,很好可是对理解没帮助,我们应该看看 Function<T, R> 的定义:
interface Function<T, R> { R apply(T in0); }
准确的说是 Function1: (T) -> R.
所以为啥现在可以了,就是因为 Function<T, ...> 里的这个 T 成了 ?super Integer, 所以它关于它的类型参数 T 逆变(contra-variant)了(Scala 的 Function[-T], Kotlin 的 Function<in T> 或者 (T) -> *)。

所以说,为什么现在可以用了,就是因为

对于任意类型 <R>
Box<Integer>#let(Function<?super Integer, R>) 可以收 Function<Number, R> 类型的实例了

为什么要有输入/输出两种情况,就是比较对象顺序上的差异(我也不知道为什么)
为什么要有型变性,是为了完整化类型系统多态(polymorphism)的代码复用
+ 如果有某个收某类型 A 的操作 Op<A> { void op(A); }, 则对于所有的 Op<A0: ?super A> { void op(A0); } 它肯定能够 op((A) x),因为它连 A0(如 Number) 都能收自然能够收 A(如 Integer)
+ 如果有某个返回某类型 T 的操作 Ret<T> { T get(); }, 则对于所有的 Ret<T1: ?extends T> { T1 get(); } 它肯定能够 (T)get(),因为它连 T 的子类型都能返回,为什么不能返回 T

然后 Kotlin 的 * (就是说在某个「位置」被一切参数兼容,比如 Consumer<in *> 可以收 Consumer<Int>, Consumer<String>, ...) 在 in 的位置是 in Nothing, out 的位置是 out Any?

Nothing
是 Kotlin 里一切类型的子类(bottom type)、Any? 则是一切类型的超类,所以区间 Nothing..Any? 就代表可接受一切类型
不过区间好像是包含两个比较的,a<=x&&x<=b 代表 x in (a..b), 类型检查只用判一次超类链


岂止是没区别,单就泛型看(这还不提 Kotlin 化腐朽为神奇的 T?, (?.) (?:) 操作)都是天壤之别呢,你去看那么多 Java 库,他们类似 Action<T>, Consumer<T> 这种都不得不对每个受参的方法写 Action<? super T>
那种雷轰感,没写过是不会明白的……

Kotlin 的 in/out 都是在类型变量声明处,此外对于 <A, B> fun copyArray(dst: Array<A>, src: Array<B>) 为保证类型安全和代码复用可在 Array<...> 里填 out B, 它会禁止对 set(Int,B) 的访问
(因为如果允许,实际上意味着 (ary as Array<Int>).set(Int, Number) 可以被使用,因为 src 可以是任何 Array<T> where T: Number,这是败坏类型安全性的)(给填 in A 也是可以的,效果一样)

成熟个毛线啊,Java 简直老掉牙了!Kotlin 写十行的代码 Java 不得不写 20 行,有些 Java 程序员能写 40 行,带上所谓的内联文档和注释和『完全覆盖』的测试!

和兼容 Java 没有关系,Java 对泛型兼容也主要是编译器上下工夫,类文件格式其实是没有变化,只是加了点元数据


就是这样
Forwarded from dnaugsuz
所以,对你的方法大概是用 Array<kotlin.Int>

我猜你是这么想到这个问题的:Java 里你用的是 final T[] xs;
可是如同 kotlin.Int 不是所谓的『primitive』一样,Kotlin 里也没有 primitive 的 generics array。
你是担心它有额外的性能开销?那就用 IntArray, CharArray 什么的…… 他们是自动拆箱(unboxing)优化的

你说你能保证,这可以理解(因为编译器不可能知道你到底想干什么),可问题是编译器也无法靠你的口头保证得知 arrays::get 是的确是 (Int) -> E,是不是?

计算机是死的,Array<T> 由于 Java 的泛型擦除(泛型参数只在类型检查时存在,除非你用 Kotlin 的 inline + reified type parameter),其实际存储是由 JVM newarray/anewarray 自动创建的,alength/xaload/xastore 指令来取长/访问实际数组对象。

List<T> 运行时全是 List<Object>, 知道他们的类型全都依赖类文件存的元数据
即便是编译期,你觉得你能保证,但谁知道你会不会写出 arrays[0] = Any().also { assert(Any() !is E) }?这样实际上就和无类型检查没啥区别了。
所以你要检查就写进类型系统的依赖数据,不检查就 Suppress,不要说自己可以保证,没有谁是敢保证自己的代码的。
比如说我就经常被 IDEA 自动推导的结果打脸(被打的是我自己的推导结果)。

另外,一般为了保证泛型的型变性(在 Kotlin 里,也就是输入输出方法被调用的可能性)安全,应该用 Array<*> 替换 Array<java.lang.Object>

如果你不向数组写东西(就是说它的 set(Int, E) 不会被使用),Array<kotlin.Int> 就可以了。
Forwarded from dnaugsuz
但它也是困难的,你试试写个 partial evaluation 的翻译器出来,带寄存器分配的那种,或者自己独立思考一下 Java 的反编译器该怎么写。
Dalvik 还好,不存在什么存储寄存器(link register) 什么栈寄存器维护的问题,要些 native compiler 还弄什么层次差啊…… 什么常量存储段啊…… Lua 还弄什么跳转链表……

iseki 你是大学生,不如照着 USTC 分享的那个 PL/0 来一次实验?
https://github.com/USTC-Resource/USTC-Course
Forwarded from dnaugsuz
Kotlin 里可以啊,难道 Array<T> 不是?
只不过提供了 IntArray 之类的优化(可以用 .toTypedArray() 来互化)
T: Array<Any?> 是这个意思吧?换成 Java 就是 T: Object[]
Any?: Array<Any?> 是不存在的,Any? 的确是 Array<Any> 的超类,你是要表达 T where T: Array<Any?>, Any? 吗?
T where T: A, B 的意思是,一个类型 T 的元素可能是任何既是 A 也是 B 类型的对象,也就是交集类型(intersection type)
Java 里,capture<?extends A+B>

但是我可以保证数组存的都是某个泛型 E 的元素,那么在取数组元素时就需要强转下:arrays[index] as E。但是此时会报编译警告:Unchecked cast: Any? to E。

噢…… 你的意思是 <E, ES: Array<E>> …… Array<ES> ?二维数组?也不对啊?
一般来说,能够静态检查的话都检查了,如果你说,你能保证,你就 Suppress 掉它。
比方说,
val res = RhinoJavaScript.eval("1+1")
val a: Any? = if (res == 0.0) "s0" else 1

我知道 JavaScript 表达式 1+1 求值了一定是不等于我们这边的 (0.0 as Double)
算不算『我能确保』?那你就 Suppress 就可以了,实在嫌难看你
val a: Int = a as Int 就可以了

Type checker 只是按照类型系统的规范检查你的程序,如果你确定你的建模是对的,一般情况(除非是运行时决定,这种情况就不是『静态』的类型)都可以推导/确定它的类型,
参数化类型也不是辣鸡(虽然 Kotlin 算是 Java 泛型擦除的一点改进)
Forwarded from dnaugsuz
如果只是溢出了符号位应该就可以用 toULong 的吧
呃…… 或许,你的意思是,你要从 kotlin.String 解析 kotlin.ULong
首先,我建议:不要用 String.toInt(), 不过既然 Kotlin 它就只提供了这个名字就算了…… [kotlin.text.toInt]
我的意思是,它本该叫 parseInt 或者 readInt…… 或许是我多想了

然后是,如果 Kotlin 标准库没提供 String.toUlong(radix),你又不想进行(实际上不一定正确,如果溢出的不对的话)的 toULong() 转换
你可以自己写解析算法,就用那种常用的十进制移位即可:

fun String.toULong(radix: Int = 10): ULong {
var accumlator = 0.toULong()
for (digit in this.reversed())
accumlator = accumlator*radix + digit.toInt()
return accumlator
}
#China #book #school #life 🏫📔 最近从本校的物理老师处得赠了一本 #Algorithm 算法书《算法》 Algorithms in C++ I-IV: Fundamentals, Data Structure, Sorting, and Searching by Robert Sedgewick
https://book.douban.com/subject/1116599/

这本书甚是有价值,不仅仅在它的三观、逻辑、数学、图示、新奇、编程实现上,我就不谈它的价格相比之下实在是不高了,质量上,高德纳(Donald Knuth)的学生,算法,不是盖的。

包括这本书的作者据称都是刚开始写 C++,一个离开计算机都能编程的人,又是计算机科学研究者、算法研究者…… emmm……

我从这本书(我第一次见到用 TeX 排版得这么好看的书,前一次是看 Kanru Hua 的信号处理(signal processing)论文和期刊切片,排版带内联的,虽然我没看懂)的代码块里了解到了原来还有人和我一样不那么遵循所谓的『代码风格』……
他们说,他们努力设计出了一套简洁、可移植的 C++ 编程模板(这里不是 template<> 的意思)。
尽管我不是很喜欢数学的表达方式,我还是得承认我实在找不出一点茬子了 — 比起我从其他书里,尤其是 LLVM Cookbook — 那简直无法入眼的 C++ 代码、类 — 那哪能叫设计啊?分明就是无序杂乱的方法定义!即便能够工作,却怎么也不可能达到 Algorithms 一书示例代码的层次。

虽然我的智商不高所以能实现的东西不多,但我觉得,我的代码依然相对而言较甜,而 Algorithms 一书的代码则是带点数学薄荷的咖啡,醇香微苦,不过 — 都从不油腻、不会拖泥带水让人无从入眼。

这本书里,我学(且暂时只学到)了快速查找、合并查找(不带权重和压缩的)(因为我智商低,而且最重要的是,我有别的事还要完成……)

#include <iostream>
const size_t N = 1000;
int main() { unsigned up[N], b, c; size_t it;
while (cin >> b >> c) {
auto a = up[b]; // R(a, b): up[a] = up[b]
if (up[c] == a) continue; // c R b
for(it=0; it<N; it++)
if (up[it] == c) up[it] = a; // R(it, c)
cout << b << " " << c; } }
其中的 unsigned up[N]; 也可以被泛化为 std::map<unsigned, unsigned>

这是快速查找(也可以作为实现集合数据结构的一种算法),怎么快速法呢?
是解决『传递性问题』的一种算法,它的合并操作速度较慢(所以也叫慢合并),不过判断速度很快。
我们知道,对于一个 M 个输入,它都只需要 O(1) 的时间复杂度来判断是否联通,可在更新时每次都要执行 O(N·M) 次比较 (==) 运算。

这个问题就是给你一堆『对』,如果它是新的,输出它,否则就继续下一个(C++ iostream 扫描器)。
因为快速查找(quick search)/合并(merge search)有 up(父树)所以也称树状数组。
1 2
2 3
4 0
0 1 — 4-0-1-2-3
我们的输入上有一个性质(property):forall a b c. a R b, b R c => a R c
我们管叫逻辑断言的传递性(transitive)。
1 R 2
2 R 3 => 1 R 3
4 R 0
0 R 1 => 0 R 2, 0 R 1 R 2 R 3 且 3 R 4
(因为 R(a=1, b=2, c=3) 得证 1 R 3R(a=0, b=1, c=4) 得证 0 R 4
细心的同学可能会觉得奇怪:假如我有 b - a; d - a,他们在树上不是一个树支的,可是却被认为在一起了。
其实这很正常:传递性关系是对称(symmetric) 的,也就是说 forall a b. a R b ≡ b R a
换句话说,这实际上不是一棵树,是一个树状的集合,因为集合关系 (a `是同集` b) 也具有传递性,即 『小鸡是小鸭同集、小鸭是小鹅同集,小鸡也是小鹅同集』
至于为什么像是树,这是因为集合传递性就是树状的

问题是:这不是一个逻辑问题啊,
上面的实现被称为快速查找,你可以注意到它把离散的 a R b; b R c 传递来了,至于为什么没有 a,是因为我们的实现方式是 unsigned up[N]; 数组,如果我们用的是 strcut { unsigned *up; } 就也还是一样……
我不会算法可视化,所以没有图(不像那个,我艹还是算法可视化专业研究者,计算机图形学基础啊。

至于合并查找(我不知道两颗树的权重算法和路径压缩该怎么做)(题外话,我自己设计了一个类似 Dijkstra 的 DFS 算法当然还没实现,关于狄克斯特拉算法我也自己想了6个细节,只等着写文。)

它就是
size_t i, j;
for (i=0; up[i] != i; i = up[i]);
for (j=0; up[j] != j; j = up[j]);
if (i == j) continue; // common ancestor
else up[i] = up[j]; // merge ancestor

也就是说,找到 a R b R c R … 里的这个 a,它的 parent 绝对是它自己,它就是最大的太爷爷。
(准确的说也没啥 parent 不 parent 的,一切都是临时的,比如我们每次把 c1 的 up 都置为 a,实际上只是需要一个『最大』的集合加入。换句话说,如果 c1 是以后被另一个 up=a 的 d 关联起来的,都一样)
如果他们有同一个太爷爷(也就是说,之前 up[x] = a c1 R a 的那种)
就是 up[a] = up[b] = up[c] 的情况(有关系的,我们都应用了相等关系的传递性,和传递性伴生的对称性)

就像 Rc(refcount GC)、hashmap 一样,树状数组也是只记录部分信息的,就是传递的关系,而不实际保持「继承」关系,所以才能有优化啊(要不然你只能 xs.filter { it.first == this }.exist { it.second == x } 递归下去[因为这一个表达式应该被叫做『存直接链接』],就不好了)(当然,也可以 dfs 或者 bfs。)


至于那个 O(...) 呢,书上也有在 Fundamentals 一节讲到,定义是:
对于所有 c、N0,若有 g(N) 使得对于所有 N0 < N,g(N) < c·f(N) 成立,则说 g(N) 是 O(f(N))。
就是说数学函数的变化率啦,数学喜欢 \lim_{n\to\infty}{\frac{a}{b}} 趋近于 0 表示 b 渐进地大于 a 什么的……

O(g(n)) = {f(n):存在正常量c和n0,使得对所有n>=n0,有0
唉,没一个讲清楚的,这些数学家真的会自然语言吗?真的知道啥是定语啥是状语吗?
看不懂的话,自己用反对称套一下给自己一个主语,不然算了,毕竟数学不是给常人用的。

书上还有讲状态机、形式化文法等常见计算机科学/算法问题的,不能不说是丰富丰富再丰富。
谈到算法:数组(二分查找、选择排序、冒泡排序、合并排序)、链表、递归(尾递归)、分治算法(快速排序)、哈希表、图(无向、有向无环、广度优先搜索bfs、深度优先搜索dfs、狄克斯特拉算法)、动态编程DP、线性规划、傅里叶变换、二项式、随机化、状态机、形式化文法、二分查找树BST、跳跃链表SkipList、哈希算法、非对称密钥系统……

现在时间比较不充裕,我只能暂时先写这么多。
尽管在学校里我几乎没读这本书,我还是非常感谢赠我这本书的老师,要不然,或许我自己是找不到它的,谢谢你!
更详细的书评/笔记等我以后,会慢慢发出来、写成文集。
但愿我能够理解那些烧脑精妙的算法、但愿我能设计出我所需要所有简单的算法、但愿不论我走到多远、多高,都能够保持不卑不亢,也不会忘记曾经那个真心爱着技术的自己。
#life #dev 吃完饭后先收尾了 Doku,写 AXML 和 Java Class 的读写器。

唉,事情好多
不知道何时做得完
Forwarded from dnaugsuz
我在去吃饭的路上好好想过了,

对于 return/throw/break/continue 这样的跳转行为,实现成 Nothing 表达式的目的,无非就可能是这两种:
(1) 为了语法特性需要这么做
(2) 这么做对编译器实现方便或者对语言工具处理有奇效,且对语言本身影响不大

第二条先否决掉,Kotlin 绝对不至于需要什么奇效来加速语言实现的过程,因为它的人够多。

开始我考虑限定绝句的语法 回/抛下/停下/略过 在『是逗号块』
(也就是 用户里滤出,它在穷逼VIP里的。全都让(本群去::踢了); 或者中缀链简记文法 对用户里滤出「在穷逼VIP里的」,本群.踢了(它)。 这种,这里「里」「~里的」是一种记法,也就是自定义的 . 操作符或者二元操作符)

可是后来我发现,好像无论是 Kotlin 还是绝句都没有支持那么随便的在块里加 return/throw/break/continue 指令,只能以带标签的形式使用,况且我发现,其实在不在块里不都是拿来跳转的么……
所以这个问题实际上就不存在

存在的问题是:他们作为一定是 Nothing 的表达式(如果是在分支里,就不一定了,不过实际上 is Nothing 这种判断是无意义的),是要做什么?
一般而言,对表达式的最佳实践是:值一定会被用到
所以 fun Collection<E>.add(item: E): Boolean 这种大部分情况值都会被随便丢弃的 API 不是好 API。

可是这类表达式的值总是被无视,更不要说一个一定没有值的表达式了,为什么?我想它们做成表达式不是为了在『需要值』的地方使用(比如上面的 listOf(continue, return, break, throw...) ),而仅仅是为了在可以填表达式的地方使用。

最经典的例子就是 val mustAny: Int = (x as? Int) ?: return 这种了
更恐怖的就是 do { listOf(1).isEmpty() || break; println() } while(false) 这种,利用 || && 运算的短路计算(就是惰性计算)来不使用 if 的 判断 continue……
只是因为,break 的值是 Nothing,而 Nothing 是 Boolean 的子类型,Nothing 是一切的子类型,所以它可以被放到几乎一切地方(即便在被重载 overload 的地方,因为实现类型不唯一所以无法这么搞)

总之,我想 Kotlin 这么做的原因,就是为了能在所有需要表达式的地方(而且,一定不是参数列表、接受者这种需求处)使用跳转,而这种手段只在表达式的求值情况不可被静态判断的时候才有实际意义(比如说 ?: 的情况)。
可是,我想这么做最常见的语法也大概就是 x?.a ?: return; x?.b ?: throw Exception() 这种了,也就是 Elvis 表达式空判断+跳转。(其他的我相信都不会使用,更不要提那种很阴毒的以它作为函数/方法参数的手段了)

我觉得,绝句既然是不打算保持 Kotlin 一些不好的地方的,就不能支持这种一切皆表达式的手段。
绝句应当更明确地转而提供面向『逗号文法』的控制流快捷方式,比如:

例物 喜爱程度 为
喜爱、很喜爱、非常喜爱、爱到爆炸 “emmm...”
公开的 “其实默认就是公开” 事 夸夸群() 为
晚成的量 话: 文
对用户里属人的你,话 置为判 我.度爱(你),
喜爱,"爱你!"
很喜爱,"永远给你${名字}打 call"
非常喜爱,"我不要你以为,我只要我以为"
爱到爆炸,"你的爸爸大中国"
以上情况皆,话令置为,它接"耶!"。 “只是个例子”

否则,说("emmm")、回。 “该填『不可能』”
说(话)


还好绝句有逗号文法简记,Kotlin 是没有办法很方便的支持的(不过,逗号文法的意思其实也就是明确化)

量 anyOrZero: 值 = x试作数 空则零
量 mustAny: 值 = x试作数 空则,回。


绝句的『空则』关键字可以通过直接在后面加逗号的方式切换语义,Kotlin 要想换语义就得专门定义新 ?: 语法或者提供基于 {} 块的版本(而且好像还是表达式……),如果 Kotlin 要支持,所有绝句里用逗号文法切换语义的地方(when, ?:)都得加条分支,也难怪是作为表达式的……
说起来我也是现在才知道,Kotlin 是门倾向表达式的语言
duangsuse::Echo
#life #dev 吃完饭后先收尾了 Doku,写 AXML 和 Java Class 的读写器。 唉,事情好多 不知道何时做得完
对日常脱稿拖稿的,Doku、Parser.kt(又要修改增加一堆)。
最近新加又有点难度的,Trace、kt4j、GeekSpec、GeekQuery、绝句Java类库(不是绝句后来才该有的程序设计语言)
有点绕的,Linked.List、Reflect helper、RangeMap、Trie、enumMap、基于scanNextOp只要一个参数的 infixChain、NestedList、JPanel Fibonacci sequence。
以后的,绝句解析器(至少依赖现在的 Parser.kt, infix parser)
绝句的实现虽然暂时不要(暂时是只计划翻译置 Java/Kotlin),不担保以后也不要 Doku 库的类文件读写器。
https://ice1000.org/2017/04-23-KotlinForEachBreakContinue.html

令做,[断]
(0..20).全都,[续]
若它不小10,回[断]
说(它)

🤔 我该怎么才能让这个东西,只生成基于 for iterator & break 的代码?
令做、全都 后面跟的都是块,一般都是异常捕获实现,除非我要内联???
尽管标准库的东西一般都强制内联,可是内联后就能够知道要跳转到哪里了?

令做,[断]
对0到20里的,
若它不小10,…… “跳转到哪里???它怎么知道?”
说(它)


不管内联与否都很容易做到块内返回,但返回到块外面的优化?
是不是应该用启发式往外找一层看是不是能用 break/continue?无法匹配再利用异常传递控制权?

令做,断:do {
对0到20里的,
若它不小10,break 断 “跳回[令做]块里”
说(它) } while (false);

  ……


大概只有建模好执行后才能准确的明白
#PL #PLT 为了方便大家了解一下,我在正式开始编写设计文档前会简单谈一下『绝句』程序设计语言的表达方式。
我不会提及任何设计逻辑、推导的东西,这对绝句来说应该是实现细则,只需要说「必须写明类型」、「能够智能转型」即可。

— 例子: 分二查找.jue —
“之所以叫『分二』,是因为绝句里以『二』开头也是表示数字的方法……”
“在上升序列 [自己] 中二分查找一个 [目标] 项目”
对何<项: 可比<项>>皆有
私下、尾递归的事 分二查找(自己: 行<项>、目标: 项、范围: 数域): 引数? 为
“即便函数没有『我』,绝句也把『我』视为关键字不允许赋值”
若范围.项数是一,回空。
“绝句“数”域默认和 Kotlin 一样是 a..b 全开区间;存项就是 begin <= end,用绝句说是 “始不大末”。”
“二分查找中,一般都是 begin!=end,所以不用 .存项 量(不过也不是不可以)”
量 中 = 范围的中值
判 我[中],
是目标,回中
大目标,重写(范围=范围.换末(中前))
小目标,重写(范围=范围.换始(中后))

对何<项>皆有
扩物(我: 行<项>) 为
事 分二查找(目标: 项、范围: 数域) = 分二查找.分二查找(我、目标、我的针域)
“本该名辅助函数为二分找,这里是为展示包命名空间”


— 快查集.jue —
引 绝句.环境.读写 (输入、输出、扩文)
引记法 绝句.环境.读写.扩文 「~分」
引记法 绝句.集合.组 「带」
引记法 绝句.额联.括符 「以」
引记法 绝句.额联.括符 「读、写」
常 数 N = 一千 “不一定要加空格,如果不想写类型,用<常参>”
事 入口(变长 参行: 文 “组<文>”) 为
量 亲 = 一组<数>()
对0止N里的号,亲去取位置(号)置为号。
量 b: 数;量 c: 数
“看到的『位置』『置为』『读』都使用了绝句的 存储<T> 物”
重复当输入读b读c不空,
量 a = 亲[b]
若亲[c]是a,略过。
对亲带存储里的d亲、d亲值,若d亲是c,
d亲值置为a “d亲值 = a”
输出以' '分 写b写c


— 基本词法
认为换行是 [\n\r] 里任意一个,但数行数的时候按 (\n?!<=\r|\r\n) 来数(也就是说,支持 Mac 和 Linux 式的 LF/CRLF 换行

文件开头可以是 ^#!.*$, 这一行会被跳过
空格:[ \t\n\r\u{0x3000}] — 全角空格
可选的缩进文法(就是「为……」和「,……」文法)里会预先取缩进长度,在这种文法中空格更加受到重视。
注释:
“” 可嵌套的『引号』注释
--, 直接行注释,以 [\n\r] 结尾
整数值:
'-'? … 'L'?
默认『数(Int)』,后缀 'L' 以默认『长数(Long)』
下划线不得连续出现
除非就是"0",数值部分不得以 '0' 开头
当有负号时,数值部分不应为 0, 否则编译器要提示
普通记法:
[_0-9]+
100, 1_000, -1
十六进记法:
'0x' [_0-9A-Fa-f]+
0xFF, 0xFF_FF, -0xFF
汉字记法:
… '[' '节'/'短'/'长'/'浮'/'实' ']'
零, 二, 四十一, 十, 十一, 一百, 一亿
这个是实现起来麻烦点的……
二进制记法:
'0b' [_0-1]+
0b100, 0b10_11, -0b1
浮点数值:
'-'? … 'F'?
frac = '.' digits
默认『实数(Double)』,后缀 'F' 以默认『浮数(Float)』
下划线不得连续出现
普通记法:
digits frac?
0.1, 0.23, 1.00_37
Exponent记法:
digits frac? [Ee] '-'? digits
0.1e3, 0.1E23, 1.0e-23
转义:
'\' [tbnr\]
'\u' hexDigit*4
若在 "" 中支持 "$
字符:
'\b', '.'
支持转义的一个字符
字符串:
char term = (anychar) ~('\'|term) / escape
常量字符串: '"' char('"')* '"'
内联字符串:'"' (char('"') ~'$'|'$' Name | '${'Expr'}')* '"'
长段文法:缩进块 <<长段 Name 为
名字:任何Kotlin里有效的标识符
'『' (anychar)+ '』'
真假:'真'/'假'
空:'空'

这里,准确的说对于绝句而言,词法是不能和语法分开谈论的。(因为它的解析过程不仅仅是上下文相关,而且还能够动态,虽然我在设计上很克制,只允许在导入块添加自定义关键字/二元/后缀运算符)
— 注意的一点是:绝句里没有一元的 +, 你可以认为这是相对 Kotlin 的一个倒退,但我觉得,我讨厌 +0==-0 这种事情、觉得零不应该分什么正负,也讨厌把一些可以默认的东西显式写出来,即便这是正确且在理论上也优雅的。

本来我想弄好 Parser.kt 再说的,可既然现在写了就继续吧……