更新修改:
- 在类型定义中添加
=
提高可读性 - 修改了实现语法
- 解释了设计思路
- 添加了更多关于
&
对类型的影响 - 修改了关于枚举项的设计
- 添加了一个混入的例子
# 定义基础数据结构和泛型, type 后的第一个内容为类型名称
# | 符号后 @ 符号内容为枚举项名称
# `Option0 .| Option1 .` 作为 `Option0 @ () | Option1 @ ()`
# 的语法糖?
type MyType = Int | IsRunning @ Bool | MyStruct[T: Int | Uint | Bool] @ {
typeName: match type T {
Int | Uint => "Number",
Bool => "Bool",
},
value: T,
} | MyArray @ Array[Int | Uint,8] | MyTuple @ Tuple[tring, Bool] | "A value can also be a type" | 1002 | 1003
# 只存在一个成员的 Tuple 必须使用
# Tuple 类型名称和泛型声明, 其他 Tuple 可以用括号简写
type Tuple0 = ()
type Tuple1 = Tuple[Int]
type Tuple2 = (Int, String)
type Tuple3 = (Int, String, Bool)
# ...
# 这样即使只是定义一个简单结构体或者类型别名也是符合直觉的
type Vec[T] = {
this: T,
next: Vec[T]
}
# 函数的定义
fn log_out_str(A: String) {
print(A)
}
# 使用 pure 作为关键字定义纯函数
# 纯函数强制禁止使用造成副作用的内容
pure add[T: Int | Uint](A: T, B: T):T {
A + B
}
# trait 是一个只有函数头没有函数体的定义
# Self 和 self 用于代指实现该 trait 的类型
# 的类型和对象, 作为语法糖 self 可以不用指定类型
trait io(self): Result[() | Self, String]
# 使用 pure 修饰使 trait 的实现只能为纯函数
pure trait showable(self): String
# trait 为类型定义添加上了更多限定
type MyResult[Ok, Err: showable & io] = (Ok | Err)
# 并列类型中的 trait 限定
# & 的优先级没有 | 大, 所以下面两段代码等价
type ShowableOrIO = JustShowable @ showable | JustIO @ io | Both @ (showable & io)
type ShowableOrIO = JustShowable @ showable | JustIO @ io | Both @ showable & io
# & 依旧可以用来限定类型
type ShowableNumIO = (Int | Uint) & showable & io
# 下两种类型等价
type Num = (Int | Uint | String) & (Int | Uint | Bool)
type Num = Int | Uint
# 下两种类型等价
type Node[T] = {
this: [T]
left: Node[T]
} & {
left: Node[T]
right: Node[T]
}
type Node[T] = {
this: [T]
left: Node[T]
right: Node[T]
}
# 下两种类型等价
type Many = (Int, String) & (Int, Bool)
type Many = (Int, String, Int, Bool)
# 下两种类型等价
type = MyArray @ Array[Int, 8]
type = MyArray @ Array[Int | Uint, 8] & Array[Uint, 8]
# trait 限定也可以用在函数声明中
fn log_out_str_by_trait[T: io](A: T): Result[() | Self, String] {
A.io()
}
pure to_string[T: showable](A: T): String {
A.showable()
}
# trait 也可以用限定, 甚至可以添加函数体
# trait 的函数体是该 trait 的默认实现
trait out_as_string[Self: showable & io](self): Result[() | Self, String] {
self.log_out_str_by_trait(self.to_string())
}
# 使用 impl 作为关键字为一个类型编写 trait 的更多实现
# Tuple2 的定义为 type Tuple2 (Int, String)
impl showable(self: Tuple2): String {
val (num, str) = self;
"(\(num), \(str))"
}
# 其他的想法
# - trait 和 trait 的实现如同函数一样也需要被引入才可以使用
# - 使用 func 替代 fn, 用来和 impl, pure 对其,
# 避免 fn 比 pure 少两个字母导致的 fn 乱用
# 私心上希望 非纯函数 的声明方式越复杂越好
# - trait 要是配合函数重载, 允许多个 trait 重名
# 可以大大提升代码多样性
设计思路:
- 月兔的 OO 机制很有意思, 完全围绕单函数和类型绑定来设计的这个设计中的 trait 和类型设计也希望尽可能配合这个思想保留尽可能多的自由度
@
符号的采用目的是为了和模式匹配中的 pin 操作符@
保持一致性- 面向 wasm 的月兔天生是跨平台的一把好手, 更零散的抽象代码可以更方便依赖单文件脚本或者较小的库来传播
- 尽可能保持函数式的强大和 ml 的一些设计思路
抽象思路:
# lib/a.mbt
pure trait showable(self): String
trait outputInt[Self: Int & showable](self): Result[(), String] {
print(self.showable())
}
trait callOutputInt[Self: outputInt](self) {
val _ = self.outputInt()
}
# main/main.mbt
use @lib.a.(showable, outputInt, callOutputInt)
impl showable(self: Int): String {
self.to_string()
}
fn init() {
12.callOutputInt() // 12
}
# lib/moon.pkg.json
{
"name": "a"
}