ccc,简写c3
为了记录版本变更,已放在 https://github.com/2A5F/C3-draft/
编译器 https://github.com/2A5F/Chaoite
- 采用胖指针形式
- 所有类型均有运行时实体,泛型也是
- 尽量一切都是第一类的(first class)
- 使用引用计数
- 尽量静态分析声明周期
- 尽量只有使用了才有开销
- 强制要求
;
结尾 - 块内最后表达式可以不加
;
print('hello world');
没有printf
单引号为字符串
分号是可选的
-
mut a:[int?]; val a:[int] = 1; // 有赋值语句时建议使用这种 mut a int?; val a int = 1;
-
val a = 1;
-
变量默认不可变
不可变变量必须马上赋值val a int = 1; val a = 1;
-
val a:[int] = lazy { 2 ^ 6 };
-
-
mut a:[int] = 1; mut a = 1;
-
-
let
是语句,没有返回值let a = 2; a++; let a + 1; // 其他语言是 a += 1
-
常量是编译时决定的
一般不需要使用,不可变值会自动优化成常量const a = 1;
-
// 单行 /* 多 行*/ /* /* 嵌套 */ */ /** 文档 */
-
1_000_000
-
'${some}'
-
"asd 123"
c语言名 | 类型名 | 大小(字节) | 字面量 |
---|---|---|---|
_Bool | bool | 1,1/8 | true,false |
char | i8 | 1 | 0i8 |
unsigned char | u8,char | 1 | c"x", c'x',0u8 |
short | i16 | 2 | 0i16 |
int | i32,int | 4 | 0,0i32 |
long | i64 | 8 | 0i64 |
long long | i128 | 16 | 0i128 |
unsigned short | u16 | 2 | 0u16 |
unsigned int | u32,uint | 4 | 0u,0u32 |
unsigned long | u64 | 8 | 0u64 |
unsigned long long | u128 | 16 | 0u128 |
float | f32 | 4 | 0f,0f32 |
double | float,f64 | 8 | 0.0,0d,0f64 |
long double | f128 | 16 | 0f128 |
抽象类型大小不可确定
c/c艹语言名 | 类型名 | 字面量 |
---|---|---|
void | void | void |
null | null | |
nullptr | nullptr |
高级类型大小是变长的
c/c艹语言名 | 类型名 | 字面量 |
---|---|---|
char*/string | string | 'x', "x" |
Mutable[type] | mut type | |
Nullable[type] | type? |
名称 | c语言内 | ccc内 |
---|---|---|
指针 | type *name | mut (mut type)* name |
常量的指针 | const type *name | mut type* name |
指针的常量 | type * const name | (mut type)* name |
常量的指针的常量 | const type * const name | type* name |
引用 | type &name | mut type& name |
常量的引用 | const type &name | type& name |
指针是不安全的,必须在unsafe
块内使用
指针和引用的区别在于
指针可以运算来改变地址
而引用不能
可空的 空为 null
而指针的空位 nullptr
type?
mut type?
type?*
type?&
fun add(a int, b int):[int] {
return a + b;
}
fun main() {
print(add! 1 2);
}
-
fun add(a int, b int):[int] { a + b }
-
fun mut add(a int, b int):[int]; let add = { a + b }
-
fun add(val a, mut b):[int] { a + b } fun add(a, b):[int] { a + b }
-
并且返回值不能是可变的
fun mul(a int, b):[auto] { a * b }
-
-
fun add(a int, b int):[int] { a + b } fun add(a int, b int, c int):[int] { a + b + c } fun add(a float, b float):[float] { a + b }
-
fun add(a, b):[int] => a + b;
-
val l = x => { x + 1 }; l 1; val l2 = { it + 1 }; l2 1; val l3 = (a, b)=> { a + b }; val l4 = { a, b => a + b }; val a = (a int, b int):[int] => { a + b }; val b = {(a int, b int):[int] => a + b }; val b = { a int, b int -> int => a + b }; val c = fun add(int a, int b):[int] => a + b;
-
如果不指定那么默认自动判断捕获
fun some() { val a = 1; val b = 1; val c = |a, b|{ a + b }; } fun some() { val a = 1; val b = 1; fun c|a, b|() { a + b }; }
-
val add:[(a int, b int):[int]] = { a + b }; val add:[a int -> b int -> int] = { a + b }; fun add(a int, b int) = { a + b }; fun some(fun add(a, b):[int]) { add(1, 2); } fun some(add (a, b):[int]) { add(1, 2); }
-
val add0 = add(1, ?); val add1 = add! 1; val add2 = add(?, 2); val add3 = add! ? 2; val more = some(1, 2, ?..3, 6); val type = some(1, ?int);
同个调用只能存在一个尾部函数调用
同时接受多个函数时候需要用?=>?
或()=>?
指定some((a, b)=>?, 1, 2) { a + b }; some(?, 1, 2) { a, b -> a + b }; some(?=>?, ?, ?, 1, 2) { a + b };
fun some() { return '${?} - ${1}'; } some(); // [`a](a `a):[string]
内联函数其实是卫生宏
-
[]
表示可选 -
=
inline
[(
<其他标注>)
]:
[[
<内联返回类型>]
] <函数定义> [async标注] <函数体>
内联函数会要求调用者具有与内联函数一样的上下文
比如内联函数标注返回 void
那么调用者也必须返回 void
不写的话就代表任何情况都可以,并且没有相关影响的代码
作为类型时 async标注
也写在 inline
的括号内
inline fun some() {
return
}
fun foo() {
some();
}
展开成
fun foo() {
return
}
使用 inline return
返回一个值
inline:[int] fun some() {
val x = 1;
inline return x * 2;
}
fun foo() {
val x = some();
}
展开成
fun foo() {
val x_1 = 1;
val x = x_1 * 2;
}
但并不是所有 inline
函数都会被展开
比如作为变量传递的 inline
fun map(cb (`a)[`b] inline(loopbody), f Arr[`a]):[Arr[`b]] {
for(x in f) {
cb! x;
}
}
map({
break
}, [])
使用 await
关键字或
在一个异步值后面加上 !
来 await
fun some():[Async[int]] async {
await some();
some()!;
return 1;
}
!
实际上是后缀运算符
inline fun operator [`T]Async.self!():[`T] async {
inline return await self;
}
record Vector3 {
mut x int;
mut y int;
mut z int;
}
val v = Vector3@{
val x = 1;
val y = 2;
val z = 3;
}
-
构造函数使用首字母大写的
Self
标注record Vector3 { val x int, y int, z int; fun Self(x, y, z) { self.x = x; self.y = y; self.z = z; } } val v = Vector3(1, 2, 3);
record Vector3(x, y, z) { val x:[int] = x; val y:[int] = y; val z:[int] = z; }
record Vector3(self x iny, self y iny, self z iny) {} record Vector3 <-(x int, y int, z int) {} record Vector3 { fun Self(self x int, self y int, self z int); } record Vector3 { fun Self <-(x int, y int, z int); }
-
在结构内定义的成员和在外面定义的成员是等价的
.
在函数调用上实际是管道运算符
区别在于结构内定义可以省略一个自身参数
并且 c3 使用self
引用 和Self
类型 而不使用this
record Some { mut a int; fun add(v int):[int] { a + v } } fun add({ a } Some, v int):[int] { // no self a + v } fun Some.add(vint):[int] { // has self a + v } val s = Some@{ a = 1 }; s.add(2); // 3
并且构造函数也可以返回其他值
结构内返回其他类型的构造函数不能进行构造
也没有self
引用record Some { mut a int; fun Self():[float] => 2.0; } fun Some():[Some] = @{ a = 1 }; // no self fun Some.Self():[Some] { a = 1 }; // has self fun Some():[int] => 1;
-
对于结构的分部定义,只能在同个包并且同个模块内
record Some { val a int; } record Some { val b int; }
-
record Some { fun ~Self() { } }
的几种方式
val v = Vector3@{
x = 1;
y = 2;
z = 3;
}
val v = Vector3(1, 2, 3);
Vector3 v = @{
x = 1;
y = 2;
z = 3;
}
Vector3 v = default;
val v = default Vector3;
lambda形式时必须明确具有类型名
val v = Vector3@=>{
x = 1;
self.y = 2;
print(self);
self.z = 3;
// do anything
}
子范围只能选择超集内有的内容
但构造函数可以随意增加
record Superset(a int, b int) {
val a:[int] = a;
val b:[int] = b;
}
record A from Superset { a }
record B(b int) from Superset(0, b) { b }
val a:[A] = Superset@{ a = 1; b = 2; };
val b:[B] = B(1);
val c:[B] = a; // error
enum [`T]Maybe {
of Some(val `T);
of None;
fun Self(val `T) Some(val);
fun Some(fn (v `T):[`R]):[Maybe[`R]] => case (self) {
of Some(v) { Some(fn(v)) }
of None = None;
};
}
fun Maybe[`T].FlatMap(fn (`T v):[Maybe[`R]]):[Maybe[`R]] => case (self) {
of Some(v) { fn(v) }
of None => None;
};
Maybe some = Some(1);
val some = Maybe.Some(1);
val some = Maybe(1);
Some(some, { 1 }).FlatMap{ None[int] }.Some(v => { v + 1 });
//////////////////////////////
enum Some {
of A {
val a int, b int;
}
}
val x = Some.A@{ a = 1; b = 2 };
元组同时也是优先级表示方式
1个元素的元组会自动解构
并且1个元素的具名元组可以自动构造
使用 @()
来表示元组字面量
val x = @(1, 2);
record some @(int, bool);
val x:[some] = @(1, true);
record foo @(int);
val x:[foo] = 1;
val y:[int] = foo@(1);
使用 @[]
来表示数组字面量
val x = @[1, 2, 3];
在构造函数使用@[]
来表示数组构造器构造函数
record some {
fun Self@[args] {}
}
在定义时使用相应的构造字面量来进行解构
val @(x, y) = @(1, 2);
val @[a, ..tail] = @[1, 2, 3, 4, 5];
val @{some, foo as bar} = @{ some = 1; foo = 2 };
val x = if (true) { 1 }
elif (false) { 2 }
else { 3 };
for (x in some) { }
for (x, i in some) { } // i >= 0
val count = for(x, i in some) { } else {
/* 当所有项目遍历结束后调用, 可以返回值 */
return i
};
while (true) { break }
do { continue } while (false)
while({ return false }) {}
while({ val x = false }, { return x }) {}
while({ int i = 0; }, { i < 10 }) {
print(i);
} finally { i++ }
while({ false }) {
int inner = 0;
} finally { inner++ }
while(false) {
int inner = 0;
} finally { inner++ }
while { } // inf loop
val iter = for(x in 0..10) ^ { yield x };
val arr:[Arr[Arr]] = @[];
val iter = for(x in arr) ^ { yield^ x };
val iter = while(false) ^ { yield 1 };
int^ some() { yield 1 }
val gent = for(x in 0..) int^bool {
if(!yield x) break;
}
for(x in gent, { x < 10 }) { }
^bool some() {
if(yield) { }
}
for await(x in aiter) { }
val x = case(1) {
of 0 => '0';
of 1 => { true }; // return function
else { print('no') }
}
case(1)
of i:[int] => true;
of f:[float] => false;
fun some() {
return
}
label:for(x in 0..10) {
for(x in 0..10) {
continue:label;
break:label;
}
}
fun some() {
label:
print('loop');
goto:label;
}
fun some(){
val x = 1;
:{ // block
val x = 2;
}
}
val x = :{
break 'some val';
}
fun some(){
val x = label:{
:{
break:label 'some val';
}
}
}
c3 里异常也是一种控制流
并且其实叫抛出
因为并不一定抛的都是异常,可以是任何值
类似于 yield
但是是跨层的
catch
块可以在当前块作用域的任何位置定义
catch
块必须在需要捕获的调用前面定义
catch
块将会从下往上按顺序查找
直到匹配到需要捕获的类型
然后就会中断,不再匹配上面的 catch
块
catch
是需要注册的
在 catch
注册之前 它 不会进行捕获
catch
注册表是一个单向链表结构
每个有 catch
的块都会对 catch
注册表添加一个注册结构
每个 catch
块本身就是一个注册结构
每个有 throw
的块都会对当前最后链表项保持引用
直到有 throw
的块结束或者闭包被释放
多线程一样会使用此链表
多线程会导致此链表产生分支
多线程会导致有 catch
注册的块的闭包一直持续到线程结束
|fun a() {
5 |
6 | throw '123';
8 |
|}
|fun b() {
1 |
2 | catch (any msg) {
7 |
| }
3 |
4 | a();
9 |
10 | catch (any msg) {
| // 不会执行
| }
11 |
|}
0 |b()
|fun a() {
7 |
8 | throw '123';
10 |
|}
|fun b() {
1 |
2 | catch (any msg) {
|
| }
3 |
4 | catch (any msg) {
9 |
| }
5 |
6 | a();
11 |
|}
0 |b();
默认会自动隐式标注抛出
但如果想显式标注
fun some() throws(string, int) {
throw '123';
throw 123;
}
默认的抛出不会阻止下面的代码运行
想要阻止需要使用 return throw
并且标注 throws(break <Type>)
或者自动推导
fun some() throws(string, break int, int) {
throw '123';
return throw 123;
throw 123; // 不会执行
}
try
关键字可以在调用可能会抛出的函数时使用
try
将会一旦遇到抛出就停止下面的代码的运行
并且向上抛
具有抛出中断标注的函数必须使用 try
try
会将所有抛出类型都转成 break
标注的
fun some() {
try a();
// 不会执行
}
try
块可以让停止范围限制在块内而不是函数级
try
块如果有返回值那么返回值将被转换成 maybe
/ option
/ nullable
类型 (名字待定)
fun some() {
try {
a();
// 不会执行
}
// 会执行
}
在 try
块后面使用 with
跟随 catch
来处理抛出时的默认返回值
void some() {
val r = try {
a();
} with catch (msg:[string]) { msg }
val r = try {
a();
} with catch {
of (msg:[string]) { msg }
}
}
性质是一性质不能扩展的
对结构实现的约束和提供
对性质的实现必须在结构上声明
并且必须在同一个程序集内
kind SomeKind {
fun add(o int):[int];
}
record Some with SomeKind {
val v int;
val add(o int):[int] {
v + o;
}
}
性质可以有默认实现
但如果结构同时实现了多个性质具有同个成员
那么忽略默认实现并要求结构必须实现
kind SomeKind {
val v int;
fun add({ v } Self , o int):[int] {
v + o
}
}
record Some with SomeKind {}
泛型类型必须在类型前面加上`
泛型括号 []
在左边是定义,在右边是实例
fun some(v `T):[`T] {
return v;
}
-
fun add(a, b) { return a + b; }
-
fun [`T]some(v ` v) {}
-
#[`T] fun some(v `T) {}
-
#[`T] fun a():[type] { return `T; }
-
fun some(v `T):[`T] where(`T( Eq[`T] )) { return v } fun [`T( Eq[`T] )]some(v `T):[`T] { return v } #[`T( Eq[`T] )] fun some(v `T):[`T] { return v } #[`A, `B] where(`A(num), `A( Eq[`B] )) fun some(a `A, b `B):[bool] { return Equals(a, b); }
-
泛型可以被值携带传递
泛型本身也可以携带泛型fun some():[[`T]():[`T]] { fun [`T]foo():[`T] = default return foo } fun some(foo [`T](`T v)[void]) { foo(1); foo('a'); } mut [`T]some:[`T?]; some[int] = 1; some[bool] = true; [`T]all_type_default = default; fun some():[`A[`B[`C]]] {};
-
用
`数字
来表示匿名泛型val [int]a:[`0] // 表示泛型约束为 int val [`T(int)]a:[`T] // 等价
泛型类型处于重叠时
具体取值是惰性的
只有所有泛型参数都被填充时才会开始实际计算
fun a(a int, b int):[int] {}
fun a(a int):[(b int):[string]] {}
fun a(a int, b string):[int] {}
fun a(a int):[int] {}
val b = a! 1;
// [ int * (int):[int] * (string):[int] * (int):[string] ]b
val i:[int] = b;
// i = b[int]
// fun a(a int):[int]
val c = b! 1;
// [int * string]c:[`0] = b[(int):[auto]] 1
// fun a(a int, b int):[int]
// fun a(a int):[(b int):[string]]
val d = b! 'a';
// d:[int] = b[(string):[int]] 'a'
// fun a(a int, b string):[int]
使用class
定义一个类
使用inspace
定义一个实现空间
类和性质的区别是
性质是对结构的实现约束和提供
而类是存在量化
性质不可扩展,类可扩展
对函数的类
class [`A, `B]Eq {
fun Equals(a `A, b `B):[bool];
}
inpsace Eq[int, int] {
fun Equals(a int, b int):[bool] {
return a == b;
}
}
Equals(1, 2);
1.Equals(2);
对泛型实现
class [`T]Eq {
fun Equals(a `T, b `T):[bool];
}
[`A]inspace Eq[Arr[`A]] where(`A( Eq[`A] )) {
fun Equals(a [`A], b Arr[`A]):[bool] {
if(a.length != b.length) return false
for(val i in a) {
if(!Equals(a(i), b(i))) return false
}
return true
}
}
一次性实现多个
inspace Eq[int, int], Eq[float, float] {
fun Equals(a int, b int):[bool] {
return a == b
}
fun Equals(a float, b float):[bool] {
return a == b
}
}
类依赖会要求实现这个类之前必须实现依赖的类
class [`T]Some( Eq[`T] ) {
fun some(t `T);
}
同时存在类内实现和独立定义
并且签名完全重复时
优先使用独立定义
如果需要使用类内实现
可以用::
在目标名字后面加上路径
或者使用using
块
class [`T]Some {
some(v `T);
}
inspace Some[int] {
some(v int) {};
}
fun some(v int) {} // 优先使用
some(1); // 使用独立定义
some::Some[int](1); // 使用 inspace
using(Some[int], Other[xxx]) { // 使用 using 块
some(1);
}
fun foo() using(Some[int]) { // 函数级 using 块
some(1);
}
fun [Some[`T]]bar(v `T) { // 泛型模式匹配
some(v);
}
class A[`T] {
fun some(v `T);
}
class B[`T] {
fun some(v `T);
}
inspace A[int], B[int] {
fun some(v int) {}
}
// some(1) == some::A[int](1) == some::B[int](1)
互斥组 | 情况(优先级大小↓) | 分配 |
---|---|---|
2 | new 标注 |
堆 |
1 | 基础类型 | 栈 |
1, 3 | 无法确定大小,装箱,多态,指针,引用, 闭包 | 堆 |
2, 3 | stackalloc 标注 |
栈 |
大小过大的 | 堆 | |
具有复制传递性质 | 栈 | |
2 | 其他 或 auto 标注 |
堆 |
具有无法确定大小那一条的类型不能标注 stackalloc |
new val x = 1; // 堆
stackalloc val v = 'a'; //栈
没有命名空间,只有模块
不在文件头写的话,整个文件都是独立的模块
而不会并入全局模块
同一个父级模块内不能有除了函数外的模块成员名和模块名重名
也就是说函数可以和模块合并
普通模块只能包含定义
单文件模块可以包含任意代码
module path.to.Name; // 文件头
export val a = 1; //
module path.to.Name { // 局部模块
export module sub.Name {
}
}
using path.to.Name.a, path.to.Name.b; // 全文件引用
using path.to.Name import a, b; // 导入部分内容
using path.to.Name as NewName import a as b, c; // 创建别名
using(path.to.Name) { // 局部引用
using(path.to.Name) import a, b {
}
}
fun some() using(path.to.Name) {
// 函数级局部引用
}
using './path/to/name.c3';
// 按文件路径引入,只能引入没有在文件头定义的模块
using './path/to/name.h3';
// 引入定义文件
using link './path/to/name.lib';
using link './path/to/name.dll';
// 指定链接
using './path/to/name.c3lib';
// 引入 c3 库
using './path/to/name.h';
// 引入 c 头文件
// 目前没有支持 c艹 的打算
在名字后面用::
指定模块路径
Some::path.to.Name; // 不引入直接指定模块
export path.to.Name; // 重新导出
export path.to.Name import a, b; // 重新导出部分
export path.to.Name import a as c, b; // 重新导出部分并重命名
export using path.to.Name; // 引入的同时重新导出
// a.c3
module()
print('loaded')
// b.c3
using './a.c3'
// c.c3
using './a.c3'
using './b.c3'
// > loaded
module x() {
module a.b.c() {}
}
在()
括号内描述需要建立别名的类型或者类型运算
type A(B);
-
叠加态
type s(a * b); // 同时是a也是b
-
or
type s(a | b); // 或运算,满足a或b任意一个即可
-
and
type s(a & b); // 与运算,要求满足a和b都有的部分
-
add
type s(a + b); // 和运算,要求满足a和b的所有内容
-
sub
type s(a - b); // 减运算,从a中排除掉b的部分
-
dif
type s(a !& b); // 对称差集,要求a和b之间不重叠的部分
-
not
type s(!a); // 非运算,要求除了a以外的所有情况
类型运算可以级联,既多个括号,一步步的缩小范围
这里的 num
是一个抽象类型,表示所有数字,不具有实际大小
type x(num)(float - int);
在泛型标注内的泛型名后带上括号来要求泛型前置依赖
前置依赖可以是值也可以是其他类型
前置依赖表示这个泛型必须是括号内类型运算结果的子类型
也可以用 `()
来表示一个匿名前置依赖
fun [`n(num)]add(`n a, `n b):[`n] {
return a + b;
}
add[int](1, 2);
add[float](1.5, 3.14);
add[1](1, 1);
对于数字字面量类型可以进行范围运算
type x(int)(> 0);
type x(> 0); // 与上面等价,自动推导出 Int
type x(> 0.0); // 推导出 Float
type x(< 0);
type x(>= 0);
type x(<= 0);
type x(0..5);
type x(0<..5); // 不包括 0
type x(0..<5); // 不包括 5
type x(0i);
type x(0i32);
type x(0i64); // 只能是 i16 类型的 0
type x(0f);
type x(0f32);
type x(0f64);
普通运算符不能连用,必须明确可区分
-
中缀运算符
fun operator (a string) + (b string):[string] { } fun operator string.self + (b string):[string] { } fun operator (a string) + string.self:[string] { } val x = 'a' + 'b';
-
前缀运算符
fun operator -(some int):[int] { 0 - some } val x = -1;
-
后缀运算符
重载时,后缀运算符的参数不能和中缀运算符的第一个参数重复inline:[Type] operator (a Type)? { inline return Nullable[a] } inline [`T(FunctionKind)]operator(f `T)! { // `T is * -> * -> ... // #Self 表示这个函数的类型 // #self 表示这个函数自身 // $0 表示第一个参数 // ``${nameof(`T.head)}`` 不会影响编译结果,但是会影响代码提示 fun operator foo(``${nameof(`T.head)}`` `T.head):[`T.tail | #Self[`T.tail].inline.tail] { case(`T) of [any -> FunctionKind] => f($0, ?..)! else f($0) } inline return foo }
第一类运算必然是前缀的
从左向右的
第一类运算很像调用运算符重载
但是第一类运算必须有且只有一个参数
val a = (1 +);
val b = a b;
struct Some {
fun operator self(other int):[int] {
return other + 1
}
}
val x = Some();
val y = x 1;
// 2
fun operator string.self(other int):[string] { '${self}${other}' }
val a = 'a' 1;
// 'a1'
fun operator foo(other int):[int] { other + 1 }
val b = foo 1
// 2
record Some {
fun self(other int):[int] {
return other + 1
}
fun self(index int) operator =(value int) {
print(index, value)
}
}
val some = Some();
some(1);
// 2
let some(1) = 2;
// print: 1 2
fun string.self(other int):[int] { '${self}${other}' }
val a = 'a'(1);
// 'a1'
越上面优先级越低
运算符 | 结合性 | 备注 |
---|---|---|
a =op b |
右 | |
a ` | , |
|
a & , && b |
左 | |
a >op , <op , ==op , ` |
op, &op, !op` b |
左 |
a +op , -op b |
左 | |
a *op , /op , %op b |
左 | |
a **op b |
右 | |
a ^op , ..op b |
左 | |
前缀运算符 | ||
后缀运算符 | ||
a ?op b |
左 | |
f ( ) , ?() |
左 | 调用,语法特性 |
a [ ] |
左 | 类型构造,语法特性 |
[ ] b |
右 | 类型构造器定义,语法特性 |
a . , ?. id |
左 | 取成员,管道运算符,语法特性 |
运算符 | 用途 | 类型 |
---|---|---|
- a | 让值变成负数 | 数字 |
a + b | 加运算 | 数字 |
a - b | 减运算 | 数字 |
a * b | 乘运算 | 数字 |
a / b | 除运算 | 数字 |
a % b | 模运算 | 数字 |
a ** b | 幂运算 | 数字 |
! b | 逻辑否 | 是否 |
a && b | 逻辑与 | 是否 |
a || b | 逻辑或 | 是否 |
a == b | 相等 | 相等类 |
a != b | 不等 | 相等类 |
a > b | 大于 | 比较类 |
a < b | 小于 | 比较类 |
a >= b | 大于等于 | 比较类 |
a <= b | 小于等于 | 比较类 |
a !< | 不小于 | 比较类 |
a !> | 不大于 | 比较类 |
a ! | 可变化 | 类型 |
a ? | 可空化 | 类型 |
a ^ b | 生成器 | 类型 |
a ^ | 生成器 | 类型 |
^ a | 生成器 | 类型 |
a ++ | 尾自增 | 数字 |
++ a | 首自增 | 数字 |
a -- | 尾自减 | 数字 |
-- a | 首自减 | 数字 |
a .. b | 范围 | 范围类 |
a .. | 范围 | 范围类 |
.. b | 范围 | 范围类 |
a & b | 与类型 | 类型 |
a + b | 和类型 | 类型 |
a - b | 差类型 | 类型 |
a !& b | 对称差类型 | 类型 |
! a | 非类型 | 类型 |
? a | 空检测 | 可空 |
a ?. b | 空检测链 | 可空 |
a ?? b | 如果空 | 可空 |
a ! | 异步等待 | 异步 |
运算符 | 用途 | 类型 | 是否可重载 | 是否能组合 |
---|---|---|---|---|
= | 赋值 | 可变,语法特性 | 是 | 否 |
x= | x为任何中缀运算符 | 否 | 否 | |
() | 调用,类型约束,语法特性 | 任何 | 是,仅调用 | 否 |
?() | 空检测调用 | 可空可调用 | 是,仅调用 | 否 |
a | b | 或类型 | 类型 | 否 | 是 |
未完待续
type nat(>= 0);
fun fib(0):[nat] 0;
fun fib(1):[nat] 1;
fun fib(n):[nat] fib(n - 1) + fib(n - 2);
record [`n(1..), `T(Num)]Vec case {
of [1] {
val x `T;
}
of [2] {
val x `T, `T y;
}
of [3] {
val x `T, y `T, z `T;
}
of [4] {
val x `T, y `T, z `T, w `T;
}
else {
val x `T, y `T, z `T, w `T;
#for(i in 5..`n) {
val ``v${i}``
}
}
}
// Vec[3, int]
Vec[3] v = @{
x = 1;
y = 2;
z = 3;
}
Vec[5] v = @{
x = 1;
y = 2;
z = 3;
w = 4;
v5 = 5;
}
class [`f]Functor {
fun fmap(`f[`a], (`a)[`b]):[`f[`b]];
}