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
你这指定的好像是类型上界 <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 再说的,可既然现在写了就继续吧……
duangsuse::Echo
#PL #PLT 为了方便大家了解一下,我在正式开始编写设计文档前会简单谈一下『绝句』程序设计语言的表达方式。 我不会提及任何设计逻辑、推导的东西,这对绝句来说应该是实现细则,只需要说「必须写明类型」、「能够智能转型」即可。 — 例子: 分二查找.jue — “之所以叫『分二』,是因为绝句里以『二』开头也是表示数字的方法……” “在上升序列 [自己] 中二分查找一个 [目标] 项目” 对何<项: 可比<项>>皆有 私下、尾递归的事 分二查找(自己: 行<项>、目标: 项、范围: 数域): 引数? 为 …
关于汉字数值怎么读这个问题,我这里提供一个算法:

fun <A, B> Iterable<Pair<A, B>>.toMap() = this.fold(HashMap<A, B>(10)) { m, vi -> val (v, i) = vi; m[v] = i; m }
// 上面的函数其实 Kotlin 标准库也有
val 汉位至数: Map<Char, Int> = "零一二三四五六七八九".withIndex().map { vk -> vk.value to vk.index }.toMap()


读取类似 「十一」「三百三十一」「一千零一」 这种数值表示法,可以被认为是解析类似这种模式:

(小某阶的表示)*某阶单位+(小某阶一位的表示)?
(小某阶的表示)*某阶单位+零(小某阶的表示)?

「一千」的前面是小于千的(无单位)
「五十千」的前面是小于千的(十)
所以,他们表示的意思是 (一/五十)*千
然后还可以有:
五十千二百零五
这种情况,我们解析为
[5*(十)*(千)] + 2*(百) + 5
也就是 5*10*1000 + 2*100 + 5,等于 50205。

解析的时候我们除了使用递归,也可以利用重写参数或者直接用循环结构的方法,不过用循环就有点不好了
一般来说是不直接用左递归的(因为对初学者不友好,比如 JSON 的 elements = element / element ',' elements 不如 elements = [{ element }] 清晰)
这里的 [] 里包括的项目可选、{} 里包括的项目重复多次

num(it.L < L) * L + num(it.L = L.dec())?
num(it.L < L) * L + '零'num(it.L < L)?
enum class 汉数单位(val 表值: Int) {
无(1),
十(10), 百(100), 千(1000), 万(10_000),
亿(100_000_000) /* 十万、百万、千万可以被正确处理 */
}
val base = 汉位至数.size
fun <E> Iterator<E>.partialIterable() = Iterable<E> { this }
tailrec fun Iterator<Char>.读汉数(已读: Int, 左单位: 汉数单位): Int {
var 新读 = 已读 + partialIterable().takeWhile { it in 汉位至数 }.fold(0) { x, ac -> ac*base + x }
val 单位 = 汉至位数.valueOf(tryNext() ?: 汉数单位.无)
// 如果 L > L0,「一^百^千^万」,该乘
if (单位 >= 左单位) 读汉数(新读*单位, 单位)
else 读汉数(已读+新读*单位, 单位) // 表达式也可以简化
// 如果 L < L0,「一十^二」,该加
// 都是伪代码,因为 Iterable 接口不足以用于写解析器
}

至于显示 (toString) 的算法,也就是循环,找最大可选的单位算出刚才那个乘上的个数
然后继续输出剩下的,依然是(从下面的位置)找最大可选的单位,比如千->万,如果没有就不输出这个单位、继续直到无单位(1)(或者说,零也行)为止。
(比如,对一亿这个数值你能知道它 >= 亿、然后你先写 它/亿, 继续输出 它%亿)

考虑到效率建议在一个降序排列的链表上找。

突然发现 enumMap 是不存在的东西,即便有真型参也无法解决(因为不能访问 companion object),况且有更好的方法 valueOf(String),真美。 🤔
这就是绝句扫描汉字数值的方法。
duangsuse::Echo
#PL #PLT 为了方便大家了解一下,我在正式开始编写设计文档前会简单谈一下『绝句』程序设计语言的表达方式。 我不会提及任何设计逻辑、推导的东西,这对绝句来说应该是实现细则,只需要说「必须写明类型」、「能够智能转型」即可。 — 例子: 分二查找.jue — “之所以叫『分二』,是因为绝句里以『二』开头也是表示数字的方法……” “在上升序列 [自己] 中二分查找一个 [目标] 项目” 对何<项: 可比<项>>皆有 私下、尾递归的事 分二查找(自己: 行<项>、目标: 项、范围: 数域): 引数? 为 …
就抽象和算法基本结构来说,不太谈语法(主要靠你的中文语感)提及绝句的大部分构造。

绝句是一门面向对象的编程语言(准确的说也是函数式的),它支持类型推导、静态类型、可空性、带控制流闭包,基本上可以说是 Kotlin 的扩展。

绝句的语言表达层次从小到大,依次是「常」、「量」、「言」、「句」、「段」、「块」、「体」、「构」、「件」
其中,「言」就是表达式(expression)、「句」就是语句(statement)、「段」就是(LLVM 的概念)标准块(basic block)、「体」就是类似方法体、量/变参定义的「取者/置者」这种东西
「构」就是所有「大」的语言构件(都是 Java APT 能够访问到的),比如「类」、「物」、「事」、「量」,「件」就是最基础的编译单元,一个文件。

绝句的对象数据依赖建模层次从小到大,依次是「常参(常*)」、「量」、「变参(变*)」、「例」、「物」、「类」
绝句的『方法』『函数』都叫做「事」。
其中,「类」的含义并非 class,它算是 Java/Kotlin 的 interface,「物」才是 class 的意思。
绝句把『类』设计「物」的并非是因儿戏,有成语叫『物以类聚』,尽管从 Java 1.1 的时候都有所谓的「接口」,
一些使用其他风格多态系统的语言也不把类型上『操作』的规范叫「接口」,绝句要把 class 级以下降低一个级别也是有例可援的。
绝句改名了「类」,也是因为绝句有「类例」这种特性的原因(绝句不支持 sum type(union type) 的重要因素)
为了语言的一致性不能继续叫「接口」。

绝句的『接口』也允许 default 实现,不过这种「类」被称为「混合类」

绝句的所有一级(可跨体访问的)「构」都可以设置访问限制,限制从小到大依次是「公开」、「族内」、「内部」、「私下」
对应 Kotlin 的 public/protected/internal/private
绝句支持可选的二维文法(缩进带语义),只有「为」「,」可能开启一个新缩进块。
一般而言,「为……」「,……」都能够被替换为 { …… } 文法,比如 类 老鼠 为…… 可以写成 类 老鼠 {……}
用户.存一,…… 也可写成 用户.存一 {……}
绝句还支持所谓的『逗号文法』,也就是对各种代码块/组合语句的写法,存在三种简写情况,过会会提及。

绝句所谓的『记法』是一种语法扩展方式,也就是自定义关键字和中/后缀的结合
解析器利用引…… 章节里的信息 引记法……「某中缀」「~某后缀」
引记法…… 藏「某中缀」「~某后缀」
就可以在解析输入的时候自动分词结合表达式了

绝句的 「/」 就是 (.) 点运算符的同类(语法也基本一样),不过「的」只能访问属性、「去」只能访问「事」

类 可销毁 为
事 销毁了() -- 也可叫『毁掉』
抽象的 物 很吵的东西(量 名字: 文): 可销毁 为
抽象的量 销毁消息: 文
实现的事 销毁了() = 说("$名字: 销毁消息 [毁。]")
抽象的 物 安静的东西(量 名字: 文): 可销毁 为 -- 非最佳实践,这里只作示例
实现的是 销毁了() = 说("('$名字' 被毁了。)")

例 老鼠: 属很吵的东西("🐁") 为
实现的量 销毁消息 = "吱吱!"
例 蟑螂: 属安静的东西("哔~")

例 小例子: 终端应用“一个混合类” 为
实现的事 入口(变长 参行: 文) = 老鼠去销毁了() 顺便,蟑螂去销毁了()。

「类」、「物」、「例」都是类似 Java class 的构造,他们代表了面向对象的『抽象』『封装』『继承』『[部分]多态』,有
类(混合类
物(内联、抽象)(扩物、内物、内扩物、储物、例物、标物)(类例
物里可用第一人称文法「我」(this)和「亲」(super),Mixin 时需要可以使用 亲<超类名>
物里可以有初始化器(「初,……」),它在自动生成的初始化器后执行
物也可以有同名多态的「伴生例」
当然,例的定义体也是一种物,所以它也可以有初始化器 伴生例 emmm { 初,加载库("a")。 }
物的架构器「造于(……)」可以明写 对何<甲、乙>皆有物 对儿 公开的造于(a: 甲、b: 乙): 贰(a, b) ,当然也可以有很多架构器、调用 this() 架构器,与 Kotlin 无异

「属」算是绝句(语言里称)的类型,有 别名属 文 = java.lang.String 这种(typealias),规则和 Kotlin 一样,可以对何……皆有、不能别名『绝句.额联.断止』类型。
「事」是类似方法的构造,
尾递归(「重写」文法)、中缀、算符、外部、内联
参数有 ([语者:对何皆有之]「对何<…>皆有」、变长、[函数参数]跨嵌/不嵌
「量」、「变参」都是类似 Java field/property 的构造
量可以有 getter「取者,……」
变参是量,且必须有 setter「置者,……」
它们都可以使用代理: 量『绝句』: 诗 代者,诗(唐人 王维)云,……
代理使用了绝句的反射特性 事 代为置(委托者: 绝句.镜射.取置, 新值: 值者)……
没有定义 getter/setter 的属性是类field 属性,这种属性可以修饰上「晚成」 (lateinit),当然「晚成」也可以修饰局部变量
实现/覆盖的属性的类型可以自动推导、类field 属性也可以。
「常参」只能直接定义(声明+赋值),它的值必须是编译期可知的(@纯 的事 或字面常量)
常参和变参去掉「参」即可填上一个类型,取消自动推导。
常参 N1 = 一千 作 数
常数 N = 一千
「的」「去」都是 Kotlin 里 (.) 的语义,不过「的」只能用于访问数据、「去」只能用于访问行为。(好像又说了一遍
如果要引用架构器,使用「::名字」,如果引用实例上的方法,必须使用「实例去::操作」

对于所有可以面向对象继承的构件(物),都可以指定覆写可能性:「开放」「终定」
类的成员不能是「终定」的(混入类也不可以)
对于一个物,默认是
「终定(final)」
,抽象的成员都是开放的。
一个「物」的构造器默认和这个类有相同的开放性
物可以是「密封」的,密闭的类只能在定义它的文件里有子类实现。

「抽象」可以使成员定义不包含实际体,「类」里的一切都是抽象的、「混合类」里可以标记抽象、「抽象」的 物 里也可以标记抽象

继承列表里,「属」后是真正的亲物(超类),除此之外可以实现任意数目的类。
任何类型后加「代者」造于 里可访问的变量)都可以使用 delegate pattern
如果覆盖的目标是抽象的,则必须用「实现」覆盖、否则必须用「覆写」覆盖

绝句的参数化类型可以被应用到 物/事/量/变参,是这么表示的:

对何<T1, T2, T3, ……>皆有……
对何<T1, T2, T3, ……>(T1: I1, I2, … T2: …, ……)皆有……

对何<值者>(值者: 值, 可拷贝)皆有事 又同一(这值: 值者): 值者 = 这值去拷贝() 对应 Kotlin 的 where……
对何<值者: 值>皆有事 同一(这值: 值者): 值者 = 这值 对应 Kotlin 的 type parameter upper-bound

对何<出项>皆有
物 行(初始大小: 计数) 为……
对何<项>皆有
物 动行……

别名属 啥玩意一行 = 行<*>

对何<入值>皆有
类 Consumer 为
事 accept(value: 入值): 效果 “返回效果的可以不写”

<入…/出…>对应声明处型变(生产/消费位置模型),或者说类型参数的型变性。
* 就是 Kotlin 的星型投影,没区别(而且绝句里的类型顶是值?、底类型也是断止,和 Kotlin 差不多)
「真型参」前缀可以实化内联物/事,当然属性也可以多态,不过依赖给「我」用类型参数的扩物……
至于存储<T> 是如何实现,且看下面:

//!语者 此即值
包 绝句.额联
对何<值者>皆有
内联的类 存储<真型参 值者>: 值者 为
算符的事 此即值(): 值者
算符的事 置为(新值: 值者): 效果
包 绝句.集合
对何<项>皆有
物 组 …… 为
记法「取」
记法「取」的事 存储(针: 引数): 存储<项> 为
回例: 存储<项> 为
实现的事 此即值() = 我@组[针]
实现的事 置为(新值: 值者) { 我@组[针] = 新值 }

当然真型参是不能限制什么类、例物、class、struct 什么的
duangsuse::Echo
就抽象和算法基本结构来说,不太谈语法(主要靠你的中文语感)提及绝句的大部分构造。 绝句是一门面向对象的编程语言(准确的说也是函数式的),它支持类型推导、静态类型、可空性、带控制流闭包,基本上可以说是 Kotlin 的扩展。 绝句的语言表达层次从小到大,依次是「常」、「量」、「言」、「句」、「段」、「块」、「体」、「构」、「件」 其中,「言」就是表达式(expression)、「句」就是语句(statement)、「段」就是(LLVM 的概念)标准块(basic block)、「体」就是类似方法体、…
控制流,块的表示上:

,[标签]
{ [标签] x, y -> …… }
— 当然也是支持 (→) 连字文法的,就如同对 — 注释的支持一样
隐式标签和 Kotlin 一样

控制流操作都不是表达式,不过允许「,回/抛下/停下/略过。」「,……、回/抛下/停下/略过。」简记
返回可以有标签:回[标签]
其他(停下、略过)只能在一个块里使用

引记法……「里有」 — 要不然你只能用 「枪在包里」

对楼里的家,
对家里的你,
若包里有枪,我去报告(警察、你)、略过[楼]。 “快跑啊!”

这叫做同一个块

楼.对每一, “绝句是不支持「,」块参数命名的,只能叫「它」”
它.对每一, — 人
若它的包里有枪,略过……。 “你想略过哪里?”
“当然,也可以回[楼]”

这不能说是同一个块,所以「略过/停下」都不能使用,当然「抛下」带标签也是没有意义的

当然,@[件]标记 绝句的标物也是可以使用这种「对象修饰文法」的,也就是 Kotlin 的 @file:标记

题外话,其实上面的代码本该这么写

对楼里的家,对家里的这人,
若这人的包里有枪,去报告(警察、这人)、略过[楼]。
duangsuse::Echo
就抽象和算法基本结构来说,不太谈语法(主要靠你的中文语感)提及绝句的大部分构造。 绝句是一门面向对象的编程语言(准确的说也是函数式的),它支持类型推导、静态类型、可空性、带控制流闭包,基本上可以说是 Kotlin 的扩展。 绝句的语言表达层次从小到大,依次是「常」、「量」、「言」、「句」、「段」、「块」、「体」、「构」、「件」 其中,「言」就是表达式(expression)、「句」就是语句(statement)、「段」就是(LLVM 的概念)标准块(basic block)、「体」就是类似方法体、…
常参/量/变参 定义(别人称为声明)是语句
(解量)赋值都是语句
判…[(值/属/在)],…… {以上情况皆,……} 否则,……
注意 判p { 是真、是假,都一样()、回。 } 应该是有效的
是表达式
判断,……
{以上情况皆,……}
否则,…… 是语句
若…,……否则,…… 是表达式
若…,…… 是语句
尝试,……
{接迎……(成…)?,……}
是表达式
带上 终焉,…… 就是语句了
尝试将…成Name,…… 接迎~…… 是表达式
带上 终焉,…… 依然是语句
即便可以方便一点,绝句也没引入 Java 的 union type(交集类型),来用在 multi-catch 的上面
理由是这很麻烦(而且我不知道有多大用,可能最多也就三四个 catch case,对绝句的逗号文法和函数式风格手工 union 一个最近的 type 好像也没啥),可能在未来的版本会加入。

重复当…,…… 是语句
重复先,…… 当…时 是语句

问题:如果我要
引记法……「~s」
重复先,
说("emmm... ");睡(5s)
当时间的秒数小 60 时

怎么办?
答案很简单,利用标识符强行合法化(绝句称为『』名字
重复先,说("emmm... ")、睡(5s)。
当『时间』的秒数小60时

对…里的NameOrTuple,……
是语句
对…里…的NameOrTuple,…… 是语句

回/抛下/停下/略过 都是语句
不过抛下不能带 label


重写(……) 是语句
一般而言,重写都是带名字重写的(named application)

绝句里的记法「…」的事…… 全都是中缀方法
中缀方法都是左结合的,优先级没有前缀高,但是有后缀高
这是为了让 它以a始 这样的话能够正常表达,显然比 它对r中值 (它对r.中值, 错的)更自然
一时间无法列出优先级,大部分优先级可以参照 Kotlin
包括一些关键字的软硬,也都可以取 Kotlin 的风格参照

然后中缀上还有「你」文法

你x大a或小b,表达式 (x > a || x < b) 第二人称且或—定参
你x且大a、b,表达式 (x > a && x > b) 第二人称且或—定操作

以上简写适用「且」「或」

你某人,名字。 — 某人令做,我的名字。
第二人称域文法
当然,尽管绝句没有,但接收者还是纳入了类型标记的
::show is (Int) -> String
::read is (String) -> Int
文::成文属 文.()文
绝句按照类似 Java 的「包」划分命名空间,和 Java 有一样的要求:包 某包.某子包某件 必须在 某包/某子包/某件.jue 路径下
包 绝句 是被特殊处理的,不过没有 package-info
和 Java 一样,绝句也可以在任何情况带命名空间引用某个构件

引 绝句.标物.平台
引全 绝句.集合
引全 绝句.环境的
引 绝句.环境的输入 -- 就是 import static
引 绝句.额联 藏(说)
引 绝句.区间 (长数域、短数域 成 小罐数域)

区别是绝句利用「引」文法来动态修改自己的语法
引记法 绝句.额联 藏「~前」
引记法 绝句.额联.扩符 「成」

不过,「藏」是不能藏掉原来就有的东西的(比如数::前

绝句也可以使用 partial application,「方法引用」语法当然不可以使用 partial application,不过任何「事」都可以被部分应用:打(_, 好人卡)(这人)
绝句里接收者不算参数(所以没有 Kotlin 一样直接的 extension fun/var,只有「扩物」)。

绝句和 Kotlin 一样,「事」可以被带名字的参调用,且有 optional arguments,语法与 Kotlin 无二。
Smart cast 也是实现时必须考虑的事情(同时也是实现 无常<R> 的必需品)。

所有 @……“标物” 都是修饰符,可以被应用在直接构件上,绝句也有类似 Java APT 的「标物处理器」。

标物的位置标签: 件、属性、取者、置者、置者参、类型接收者、代理(似乎要改变?)

绝句在未来还会引入「模板」这种语法
目前保护的关键字有:「模板」、「待例」、「实际」、「模块」、「断续」、「回交」、「性质推导」

语言特性:「对何皆有之」(rank-N type)、「模板」、「具名模板」、「单线程逻辑」(然后就可以针对串行逻辑 smart cast)、「此即值」(也可以用于实现 lazy)、「无例之物」(只该在标准库里用)

原来我还把「类实例」也作为额外特性设计的(而且还有「和之类型」、「类定界」、「前缀记法」emmm),后来它是主特性了
类定界说白了就是复辟 Java 的 ?extends, ?super。我当时的理由是教学目的和「检查器内部使用方便」,可后来我一想就想出了一点不带所谓 wildcard 的型变泛型类型检查,于是就作罢了。
「T定超A」「T定输A」,如果你想定义交集类型(intersection type)还可以用「T定属A属B」…… 还有什么「T定超A超B」……emmmmmm

https://www.cs.cornell.edu/andru/javaspec/1.1Update.html #Java 找到一个资料
duangsuse::Echo
绝句按照类似 Java 的「包」划分命名空间,和 Java 有一样的要求:包 某包.某子包 的 某件 必须在 某包/某子包/某件.jue 路径下 包 绝句 是被特殊处理的,不过没有 package-info 和 Java 一样,绝句也可以在任何情况带命名空间引用某个构件 引 绝句.标物.平台 引全 绝句.集合 引全 绝句.环境的 引 绝句.环境的输入 -- 就是 import static 引 绝句.额联 藏(说) 引 绝句.区间 (长数域、短数域 成 小罐数域) 区别是绝句利用「引」文法来动态修改自己的语法…
运算符:

前、后 (dec/inc)

+(加)、-(减)、*(乘)、/(除)、%(取余)
-~(取负)

大(>)、小(<)
不大(<=)、不小(>=) — 这一行括号里的表示法仅参考用
汉语里就不要用小于号、小于等于了。
取负的 -~ 只是注释,绝句不存在前缀记法,只有前缀算符

&(且) |(或) !~(取非)
(异) — 只有真假类型有
绝句的且或非逻辑都是短路计算的,也就是说 假 & 不可能, 真 | 不可能
我相信,既然绝句已经改了这么多了,不会有人觉得让 (&) 官复原职很奇怪
第一眼看了或许会觉得对短路语义强调得不明显,多看几次就顺眼了。

== (是) ===(即是)
是就是 equals,即是就是全等
!=(不是) !==(不即是) — 这一行是不依赖语言内定义的「事」定义的
Null 的操作符们:
(?.) ?. ?的 ?去
(!!) !!
(?:) 空则
空则,……
(不空) — 就是「不是空」的意思了

(在)(不在) —in
(属)(不属) —is
(作) — as
(试作) — as?
..(到) (rangeTo)

以上(中缀、算符的事……)都可以作为中缀使用,不过「非/取负」是不能作为前缀使用的……


一些内部的东西:

默认导入的一些操作符
— 位运算
包 绝句.额联

扩物(我: 数) 为
记法「位」「~位非」
“位左移、位右移、位直右移”
“位交、位并、位异” “位非”

扩物(我: 长数) 为……

特别的元方法:
代为取(仅取): 值者
代为置(取置、值者): 效果
取项(针: 引数): E
置项(针: 引数, 新值: E)
用(……) 就是 Kotlin 的 invoke(...)


因为绝句有存储建模的原因,就不必弄什么先增后增的了。
var i = 0
println(i++)
println(++i)
<=>
引记法 绝句.额联.扩符 (令并置为)
变数 i=零
说(i顺便,它令置为「后」。);说(i令并置为,它后。)


说(i令为,它后。顺便(i去::置为))


说句题外话,这是给那些执迷不悟的人用的,绝句利用二维文法本来已经可以足够好看足够短地实现什么先增啊、后减啊的,你还是要用这种带副作用的算符,那我就无话可梭了。

对何<项>皆有
物 切片迭代器(量 列: 切片<项>、私下的 变引数 针=0): 迭代子<项> 为
实现的事 下移(): 项 为
回列[针] 顺便,针令置为「后」。 “{它后}/引数::后”
— 实现的事 下移(): 项 = 回列[针 顺便,它令置为「后」。]
“是何苦呢?”

看了这些例子你肯定发现了关于「,」文法的一个细节:没有嵌套的
针 顺便,它令置为,它后。 这种
更不会来段
若p,若q,f。。 这种了

首先 「」 文法是绝句的 sectioning (Haskell
「后」实际上的意思是 { 它后 }, 当然这是因为「后」本身是一种后缀运算符,而它前面的东西缺了。「后后」、「后+1」也是可以的
「+2+3」的意思是 { x -> x+2+3 }
「2+_」的意思是 { y -> 2+y }
「+」的意思是 { x, y -> x+y }
不过「+a+」这种是不行的,中缀链只能缺少主语(就是中缀链前面的东西),或者它就是某种记法/运算符、甚至可在右边使用 _ 文法。
虽然绝句实际上也能在标准库里定义这些加法啊减法的,我觉得还是作为语言内部钦定的文法强一些。

对后缀和中缀记法的处理是不完全一致的,不过都是按照这个原则来。
上面的 () 写的是不对的,绝句同时支持全角括号和半角括号,只是要匹配才行。

至于「,」表示法的三种简记呢,首先我想谈谈它是怎么设计出来的

大概就是我在考虑 某文件=打开("emmm","rw") 这样的调用时
我觉得逗号似乎是不应该用于这个地方
其实绝句程序设计语言在开始设计前,我在写一个『绝句的Java版本』,就是可以这么写的:

/* import 了一堆被我称为名词的单例,实际上他们都该说是所谓的访问器对象。 */
小.的(燕子); 穿.着(花.的(衣));
又(年, 年).的(春天).是会(来(这里));
我.问(燕子); 为何(你, 来);
它(燕子).说(我.们.的(春天).是最(美丽.的()));

— 觉得上面的没有多大用或者让我「show code」?我有一个实用一点的例子,虽然 show code 是不可能的。
把(这人.的(朋友们).中(所有(名字.以("abc").起始().的()))).都拿去(用户表::删掉);

从(1).数到(100, (它) -> {
若((它/2).为零(), 向(终端).写("偶数"))
.否则(向(终端).写("奇数"));
});

是不是有点眼熟了?某些 Java 框架都喜欢这么干,不过据我了解某个叫 Arqullian wrap 的框架做得很难看…… 或者说被写得很难看很空。
Consumer<?> 不可能 = (Object _) -> { throw new ImpossibleException(); };
判断(他.的(名字),
倘若(它.是("蔡徐鲲"), 向(它).致敬()),
倘若(它.是(在(iKun.映射到(IKun::名字)).中()), 向(终端)::写),
否则(不可能));

当然,仅仅这样是不够的,所以我的方法是枚举了一些常见的介词(p)/连接词/助词/补语/位置(f)数量(b)/副词(d),然后在需要使用的特定子类实现里补上动名词(比如实现什么『把字句』『以子句』『位置数量定语』『从字句』),然后就可以利用 this 调用链和函数式方法以中文语序写程序。

不过,上面的代码虽然对中文来说比较自然了,绝句里还是更进一步:
判他的名字,
是"蔡徐鲲",我致敬(它)
在 iKun映至「的名字」“其实不该每次去投至”,输出写它
否则,不可能。


嘛,毕竟 「判」的分支后面也可加句号,也可不加。
引记法 ……「以为」
引记法 ……「~是傻逼」
引记法 ……「唾弃」
块实现加了句号后就不需要后面的 [去]了,但是不能加 (.), (?.),(?去) (?的) 也还是不能少
对[某事]iKun中滤出「属年轻人」里我@某事以为 我是傻逼的你,我唾弃你。
emmm
不对…… 我没用逗号记法
确保(1令为,它成文。令为,"+"接它。是"+1")

小燕子(nr),(,)穿(zg)花衣(n)
把(p)这(r)人(n)的(uj)朋友(n)们(k)中(f)所有(b)名字(n)以(p)abc(?)起始(v)的(uj)都(d)拿(v) 去(v)让(v)用户表(n)删掉(v)

看着这样的风格,我忽然明白了 sodayo 原来不该用逗号切分这种弱智的参数列表,因为中文是拿顿号分割不同意群的!!!
后来绝句就有了逗号文法,这也是我对绝句最引以为豪(当然也是喜欢,有时候也最讨厌)的一个语言特质 🙊

不过这个逗号文法,开始只是类似 Python 一样起始任何语句「块」的,但是简写也很重要啊(比如,我不可能把 若用户的钱数少于商品的价格,回。 写到两行里,而且第二行还只有一个「回」!)

这三种特化的文法,就是逗号段/单控制流或表达式简记/语句们 and 控制流简记,当然还有一个用于传递块参数的「逗号块」没计。
duangsuse::Echo
运算符: 前、后 (dec/inc) +(加)、-(减)、*(乘)、/(除)、%(取余) -~(取负) 大(>)、小(<) 不大(<=)、不小(>=) — 这一行括号里的表示法仅参考用 汉语里就不要用小于号、小于等于了。 取负的 -~ 只是注释,绝句不存在前缀记法,只有前缀算符 &(且) |(或) !~(取非) (异) — 只有真假类型有 绝句的且或非逻辑都是短路计算的,也就是说 假 & 不可能, 真 | 不可能 我相信,既然绝句已经改了这么多了,不会有人觉得让 (&) 官复原职很奇怪 第一眼看了…
然后再谈一些比较贴近语言本身的「物」:

物 数值 为……
物 真假 为……
别名属 是否 = 真假
物 字节 属数值 为……
物 短数 属数值 为……
物 字儿 为……
物 数 属数值 为……
物 长数 属数值 为……
物 浮数 属数值 为……
物 实数 属数值 为……
物 文 为……
别名属 计数 = 数
@内部 别名属 正计数 = 计数
别名属 引数 = 数

「文」和 Kotlin, Java 里的 String 一样,是不可继承的,其他类型也和 Kotlin 里一样是终定的。
是否一般是用作可变数据的

然后是集合
不过绝句里认为,只要是可以用于装一个以上值的东西都叫做集合。

按照从小到大的顺序,元一<A>..., 组<T>, 行<E>, 行列<E>, 表<K, V>, 集<E>, 合<E>, 迭<E>
他们都默认是只输出数据(不可变)的,
类似动元一<A>..., 动组<T>, …… 这种是可变的
元组一直提供到元十
之所以提供了一元元组,是为了对称,当然绝不会提供类似 Rust 和 Haskell 的元零(无意义)。
对元组来说,他们不需要去兼容某一种属(也是应该的,不然和数组就没啥区别了)以提供通用 API

操作上,
isEmpty, isNotEmpty 被译为无项存项
size 被译为项数
lastIndex 被译为引末(对应的是引始

和 Kotlin 一样,对 Java 里的原生类型(primitive) (ZBSIJFDC, boolean, byte, short, int, long, float, double, char) 也提供了拆箱的组们,比如长数动组短数动组

然后是函数
绝句提供对 SAM 方法的自动实现,无论是块、方法引用(实例方法、架构器、自由方法也即未绑定到实例的方法、partial application 的结果)
一般认为函数是有N个输出一个输出的动作
没有输入和输出的函数被绝句称为『副作用』,当然是我的叫法,实际可能是 事元零<效果>
没有输出的函数通通输出
提供 事元零<R>
事元一<T1, R>
事元二<T1, T2, R>
……直到事元十二,其实本来应该用模板写的,可绝句目前还没机会加模板特性
之后的函数变量是无法表示的,这是一个限制,我不知道 Scala 是多少,好像有跑到二十?


然后是阿猫阿狗
作用 (就是 kotlin.Unit
可抛
可闭(毕竟绝句是有 try-with-resources 的)
不常
(就是 java.lang.Exception)
无常<R> (这个就是绝句版本的 Checked Exception,你若不想检查可和 Rust 一样直接 unwrap_ok(),噢不是 作决常, 当然还有 smart cast)
一般来说,如果可能且仅可能有一种失败,绝句标准库的封装不会使用无常<R>, 而是用 R? 这样的
断止决常 (无常的唯一两个子类)
断止还是一个『无例之物』
终定的物 断止 私下造于(): 无常<*>
它不能被拿来判断也不能被拿来转型,因为 x属断止; x作断止 是常量判断
存储<T> 就是可以被赋值的东西,编译器能够在取可写属性、变参的时候能够自动将它实例到存储以方便使用
比如
储物 用户(量 名字: 文、量 男: 真假、变文 bio)
量 某君 = 用户("duangsuse", 男=真, "……")
某君的名字 ”字符串 duangsuse“
某君的名字置为"$某君的名字+1" -- 但是你不能写 "$某君.名字+1" 的
“^ 自动转型为存储<文>”
某君的名字 ”字符串 duangsuse+1“



令做(run)、令为(let)、令置为、顺手(also, (T)效果)、交给(支持 (T)*also)
有若(takeIf)
成文(toString) 成码(hashCode)

滤出(filter)、映至(map)

存一(find+不空)、存仅一(single)、皆是(all)、皆非(none)

我承诺 50% 兼容 Kotlin, 60% 兼容 Java :P……
100% 不兼容烂代码