一种兼容性更好的 Go 泛型设计 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Kulics
V2EX    Go 编程语言

一种兼容性更好的 Go 泛型设计

  •  
  •   Kulics
    kulics 2020-01-09 11:21:13 +08:00 5074 次点击
    这是一个创建于 2112 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近我在我设计的 Lite 语言中探索了一种新的泛型语法,因为 Lite 从 Go 中借鉴了不少语法,所以这种泛型语法对于 Go 可能也有一定的参考价值。

    identifier<T>这种最主流的语法比较大的问题是与比较操作符冲突,同时也与位操作符冲突,因此我不赞同这种设计。

    Scala的identifier[T]语法比前面的语法有更好的观感,但解决了上面的冲突之后又与索引语法identifier[index]产生了新的冲突, 为此Scala的索引语法改为了identifier(index)。这对于已经采用[]作为索引的语言来说效果也不算很好。

    在 Go 的草案中,声明泛型使用(typeT)的方式,这不会造成冲突,因为type是关键字,但是调用的时候依然需要编译器进行更多判断才能解决identifier(type)(params)的冲突问题,虽然它比以上的方案都好,但仍然不能让我满意。

    偶然的机会让我想起了OC中方法调用的特殊语法,这给了我一种新语法的灵感。

    如果我们将标识符和泛型组成一个整体,一起放入 [] 如何?

    我们可以得到这个语法 [identifier T], 这个语法不会与索引语法产生冲突,因为它必然存在至少两个元素,中间使用空格隔开。

    当存在多个泛型时,我们可以这样写 [identifier T, V],同样不会与现有的语法产生冲突。

    将这个语法代入 Go 中,我们可以得到下面的例子。

    E.g.

    type [Item T] struct { Value T } func (item [Item T]) Print() { println(item.Value) } func [TestGenerics T, V]() { a := [Item T]{} a.Print() b := [Item V]{} b.Print() } func main() { [TestGenerics int, string]() } 

    这看起来非常清晰。

    使用 [] 的另一个好处是,与 Go 原本的 Slice 和 Map 语法有一定传承性,不会造成割裂感。

    []int -> [slice int] map[string]int -> [map string, int] 

    我们可以造一个更复杂的例子

    var a map[int][]map[string]map[string][]string var b [map int, [slice [map string, [map string, [slice string]]]]] 

    这个例子依然能保持比较清晰的效果,同时对编译造成的影响很小。

    我已经在 Lite 中实现并测试了这个语法,在 Lite 中效果很好,没有产生歧义。

    这个设计也许值得引起讨论,我已经在 github 上提交了一个 issue,欢迎一起来讨论。

    https://github.com/golang/go/issues/36457

    23 条回复    2020-01-09 22:09:13 +08:00
    codehz
        1
    codehz  
       2020-01-09 11:35:47 +08:00
    L i s p
    直接说 S-Exp 就好了(
    codehz
        2
    codehz  
       2020-01-09 11:36:49 +08:00
    甚至逗号都不需要,直接用空格区分多参数(
    不过多参数是万恶之源,应该柯里化一下,做成 * -> * -> * 的模式(
    Kulics
        3
    Kulics  
    OP
       2020-01-09 11:40:43 +08:00
    @codehz hhhhhhh 站在巨人的肩膀上
    dodo2012
        4
    dodo2012  
       2020-01-09 11:43:29 +08:00
    var b [map int, [slice [map string, [map string, [slice string]]]]]

    这个套的眼花了都,不觉得有多清晰,使用<T>的方式,更多是大家都是这样用的,更熟悉,
    IsaacYoung
        5
    saacYoung  
       2020-01-09 11:46:20 +08:00
    <>
    Kulics
        6
    Kulics  
    OP
       2020-01-09 12:58:43 +08:00
    @dodo2012
    var b map<int, slice<map<string, map<string, slice<string>>>>>
    var b [map int, [slice [map string, [map string, [slice string]]]]]

    相比之下,我还是觉得比<T>的方式清晰一些。
    liuguang
        7
    liuguang  
       2020-01-09 14:04:08 +08:00
    换汤不换药
    thisisgpy
        8
    thisisgpy  
       2020-01-09 14:12:57 +08:00
    楼主你的 Lite 语言,运算符设计的太复杂了
    kifile
        9
    kifile  
       2020-01-09 14:14:06 +08:00
    觉得只是 [] 比 <> 占的显示控件笑了,[doge]
    kifile
        10
    kifile  
       2020-01-09 14:14:24 +08:00
    显示空间小了
    hantsy
        11
    hantsy  
       2020-01-09 14:14:47 +08:00
    用 Java 多了,还是感觉<>好
    inhzus
        12
    inhzus  
       2020-01-09 14:14:58 +08:00 via Android
    可能是我 go 写太多了吗?我觉得楼主最后举的例子 go 的例子看起来挺显然的…
    imnaive
        13
    imnaive  
       2020-01-09 14:50:29 +08:00
    这个不是设计,是一种语法吧
    fcten
        14
    fcten  
       2020-01-09 15:02:34 +08:00
    "identifier<T> 这种最主流的语法比较大的问题是与比较操作符冲突,同时也与位操作符冲突,因此我不赞同这种设计。"

    这个前提就不对。操作符和类型声明出现的位置完全不一样,在解析成 AST 之前就可以区分清楚了,对于编译器来说是属于比较容易解析的语法。
    就比如括号 ( ) ,非常常见的符号,并且有多种语法,也没有冲突的问题。

    语法首先是为语义服务的。先设计功能,再设计语法。所以,到底冲不冲突,最终是要看该语法被用来支持哪些语义。用其它语言的泛型设计来推断 Go 的语法本身也是有问题的。
    cyspy
        15
    cyspy  
       2020-01-09 18:35:58 +08:00
    scala 没有索引语法,只是 apply 函数而已
    Kulics
        16
    Kulics  
    OP
       2020-01-09 21:56:05 +08:00
    @thisisgpy 的确是复杂,一开始特性少还好,后来特性越来越完备,复杂性就升上去了。只要功能多,复杂是必然的了。
    Kulics
        17
    Kulics  
    OP
       2020-01-09 21:58:20 +08:00
    @kifile 主要还是类似 s-expr 的语法比<T>形式的界限看起来清晰一些,把[]换成<>其实也会比原来的看起来清晰。
    Kulics
        18
    Kulics  
    OP
       2020-01-09 21:59:21 +08:00
    @hantsy 可是不适合 go 啊,go 草案已经排斥了<>。不然也不会有机会来讨论这个语法。
    Kulics
        19
    Kulics  
    OP
       2020-01-09 21:59:41 +08:00
    @imnaive 这么说也对,语法设计。
    Kulics
        20
    Kulics  
    OP
       2020-01-09 22:00:49 +08:00
    @fcten 曾经我也是这么想,直到后来自己写了个编译器才发现问题。
    Kulics
        21
    Kulics  
    OP
       2020-01-09 22:03:39 +08:00
    @cyspy 你说的没错,的确不适合已经用[]去处理索引的语言。
    saltsugar
        22
    saltsugar  
       2020-01-09 22:06:08 +08:00
    第一眼看过去就是 lisp 啊,不过确实挺好。
    对我这个对 go 语法还有点陌生的人来说,看的轻松。
    saltsugar
        23
    saltsugar  
       2020-01-09 22:09:13 +08:00
    看惯了 c/c++, 现在看 go 总是要转换一下思维。
    现在特别赞同傻白甜设计。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3079 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 12:24 PVG 20:24 LAX 05:24 JFK 08:24
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86