审核中的帖子不能编辑真讨厌
有聊天群吗,沟通感觉更方便
- 文档中的let mut没改为var
- 文档可以增加数据类型的介绍吗,比如二进制怎么表示,有u8,u16这种类型吗,
- 如果支持不同的数据类型,最好增加一个num的trait,并且这个num可以加减乘除
- 实现3貌似就要支持操作符号重载,建议搞个简单点语法,比如 fn +(){} 更直观
- fn关键词感觉其实也没必要,rust和js都有匿名函数,感觉可以学习coffeescript的函数声明,(){}就是函数,需要的时候再赋值给变量
审核中的帖子不能编辑真讨厌
有聊天群吗,沟通感觉更方便
你好,收到建议。
关于用户群,可以添加MoonBit小助手:moonbit_helper,添加后小助手会邀请你进入用户群~
补充下第5点,
let x=()->Int {
}
这里要写let,感觉还是有繁琐,感觉可以学习golang,用:=来做变量声明
x := ()->Int {
}
就简单多了
继续补充第5点, 如果参考golang := 替代let,那么还需要一种语法替代var才比较直观,我建议用 &= ,&的语法含义通常是指向内存地址的指针,表示可变也直观
let mut
,var
才是 deprecated,你是不是说反了u8
和 u16
暂时没有Number
这个 trait 加到内建定义里。但用户随时可以自己定义一个:trait Number {
op_add(Self, Self) -> Self
op_sub(Self, Self) -> Self
op_mul(Self, Self) -> Self
op_div(Self, Self) -> Self
op_neg(Self) -> Self
}
由于 MoonBit 的 trait 有类似 Go 的 structural 行为,所有内建的数字类型自动就会实现你定义的 Number
trait,不需要显式实现。op_add
这种特殊名字。因为这不是一个高频需求,感觉没有专门开特殊语法的必要fn
。我们有匿名函数,fn
不写名字即可:fn (x) { x + 1 }
。最近可能还会加一个更方便的匿名函数语法(还是用 fn
关键字但更简单。细节还在讨论)。let 变量 = 匿名函数
的问题是写不出递归的 local function。在 FP 写法里递归的 local function 是很常见的let 变量 = 匿名函数` 的问题是写不出递归的 local function,这个其实可以用 @ 指代当前函数(语法来自coffeescript),如果嵌套的,可以先把 @ 赋值给一个常量。
如果不用js的lambda,也可以考虑rust风格的 |x:Int|{},
这样。
没有u8,如何表示二进制的文件,比如一张图片?
我看了下文档,文档的操作符重装没给出具体的参数个数,建议给一个函数签名,写起来比较方便。
二元运算符是两个参数,一元运算符是一个参数,op_get
是自己和 index 两个参数,op_set
是自己、index、新值三个。
文档稍后会更新一下。
@
来这种特殊自指来处理。加上 local function 定义的 fn f(...) { ... }
语法和 toplevel function 是一样的,所以我觉得这个 local function 语法没有去掉的必要。u8
,但有一个内建的 Bytes
类型,是 u8
数组的语义。每次对 Bytes
get 和 set 的时候,虽然类型上是 Int
,但实际操作的只是一个 byte说实话,多层的匿名递归真不是开发程序常见场景。
大家写法可能更多是:
fn x(s){x(s)}
x:=(s){x(s)}
可以不用支持 @
想写递归,就先给函数绑定常量吧。
不过我感觉 x:=
和 x&=
这种语法声明函数、常量和变量,比 fn x
和let x
更优雅,
因为这里暗示函数是一等公民,和其他数据类型一样
明白,文档还没看到Bytes类型,不过感觉是不是会有更多性能开销,我感觉可以有类似JS的Int,但是最好还是提供一套 u8、i8,u16,i16 …的数据类型,方便一些,用不到的人也可以忽略。
比如我开一个扣费系统,必须确保扣费是正数,如果用u64,我就很有安全感。
还有很多时候,我会用到u8的 overflow add
做图片处理的时候,经常会用到这个
除了多层还有互递归。给函数绑定常量再填回去的做法,会把递归变成 deref + indirect call,严重影响性能的。
x := ...
允许递归也有一些问题。因为 x := x + 1
应该当成递归吗?如果前面已经有一个 x
了,那预期的语义应该是用旧的 x 算一个新的 x,而不是递归。但如何判定哪些情况是要递归,哪些情况是不要递归,就会搞得很复杂。
let
的好处是,每一个声明都由一个关键字开启,阅读起来非常醒目。像 x :=
这种语法,如果要支持在 x
的位置放模式匹配,那语法又会出歧义问题。然后有了 let
那 x :=
就比较鸡肋了。所以以前我们其实有过 x :=
,后来删掉了。
这个我们未来应该也会考虑
如果 x 是一个函数
x := x + 1
应该是编译错误吧,函数怎么加+1,函数不支持+1啊
等价的语法就是
let x = (){
let x = x+1;
}
感觉是会编译报错的
而且,位置放模式匹配,这个我不理解什么意思
如果要实现编译器也比较简单,
先拆分词法, 去掉注释,生成一个数组 , [“xxx”,“:=”]
然后遇到 := , 直接把前面的一个变量名认为是 let ,
如果前面不是变量名,那么报错
另外变量声明和rust一样是有作用域的,超出作用域,变量就释放了
比如
let mut x = 1;
{
let x = 2;
}
dbg!(x) // 这里还是1
另外醒目的问题,其实是语法高亮的事情,与这里写法设计无关
x
不是一个函数。x
是一个 Int
。因为 x :=
的语法不止可以定义函数,还可以定义其他类型的东西。如果要给函数的 x := ...
开递归的洞,那其他类型(比如 Int
)要允许递归吗?允许那值的递归语义不对,不允许那函数和其他类型就(悄悄地)产生了行为不一致。
放模式匹配的意思是 let Some(x) = ...
或者 let [ x, y, z, .. ] = some_array
这类东西。这时 =
前面可以有任意长度任意深度的复杂 pattern,歧义就解不掉了。
用let mut可以接受,且对基于LLM AI的代码生成可能还更友好一点。
为了完善类型系统,[^a-z]
ASCII符号在MoonBit里使用的频率占比已经够高了,再引入:=
、&=
这些符号组合,则符号产生的视觉干扰已经到了超Go赶Rust的地步(语法高亮也不能从根本上优化这个问题),个人认为有些得不偿失。