凹语言中文语法探讨(三):控制流语句

说明

上一帖讨论了函数调用相关的语法,本贴讨论控制流语句:

  • 条件语句
  • 循环语句
  • 分支语句

下面列出现有的设计与我想到的备选方案,欢迎大家提出更多的备选方案。

条件语句

凹英文版的条件语句是:

if x > 0 {
    print("x is positive")
} else if x == 0 {
    print("x is zero")
} else {
    print("x is negative")
}

凹英文版的特点是条件不用()包裹,而分支语句必须用{}包裹。

方案1. 凹中文版的原始设计如下:

若x > 0则:
    曰:"x是正数"
又若x = 0则:
    曰:"x为零"
否则:
    曰:"x是负数"

这里又若否则都是中文关键字。

这个设计的优点是简洁且符合中文习惯,缺点是的搭配容易产生“文言文”的印象。

方案2. 如果把关键字改得更加接近现代白话文,且用()来包裹条件,就可以去掉

如果(x > 0):
    打印:"x是正数"
又如(x = 0):
    打印:"x为零"
否则:
    打印:"x是负数"

方案3. 用()符号表示条件,将条件表达式和分支表达式合并起来,组成类似于match的模式匹配表达式

如果:
    (x > 0)打印:"x是正数"
    (x = 0)打印:"x为零"
    () 打印:"x是负数"
。

这里()之内的是要判断的条件,因此()表示无条件,即相当于否则
这里的()也可以换成其他的包裹性符号,如||[]{}等。

小结:

条件语句三个方案:

  • 若。。。则。。。又若。。。否则。。。
  • 如果():。。。又如():。。。否则:。。。
  • 如果:()。。。 ()。。。()。。。

循环语句

凹英文版的循环语句是:

for i := 0; i < 10; i+=1 {
    println(i)
}

这是典型的三段式for循环,并且可以灵活的省略掉其中一段来模拟whileloop等。

方案1. 凹中文版的原始设计如下:

从i=0,到i>=10,有i++:
    打印:i
。

这里的关键字是、和,对应于for里的三个段落。只不过处于中文表达习惯,用的是,后面应当是循环终止条件,和英文的条件正好反过来。
如果需要和英文一致,也可以把换成

从i=0,若i<10,有i++:
    打印:i
。

这个设计挺简洁,也很清晰,但缺点是三个关键字搭配有些生硬。真正通顺的语句应当是:

从i=0开始,到i>=10为止,有i++:
    打印:i
。

方案2. 用更白话的关键字,且用()包裹条件:

从(i=0)开始,到(i>=10)为止,每次(i++):
    打印:i
。

从(i=0)开始,只要(i<10),每次(i++):
    打印:i
。

这样写和自然语句就几乎相同了,缺点是输入量过大。

实际上,英文版的for循环,三个条件的关系也是比较生硬,不符合自然语言的,我们之所以觉得自然,是经过了大量的实践逐步习惯的。

因此,可以考虑不采用三段式的循环:

方案3. 用几个不同的语句来表示不同类型的循环:

// 相当于while循环,只有一个条件,`i++`不需要单独放置,自然放在循环体内即可
i := 0
每当(i<10):
    打印:i
    i++
.

// 需要判断终止条件时:
l := 读取下一行:
直到(到达末尾:l):
    打印:l
    l = 读取下一行:
。

// 访问某个集合,相当于 for range
xs := [1, 2, 3, 4, 5]

遍历 xs,有x:
    打印:x
。


// 无限循环
循环:
    打印:"hello"
    若...则:跳出
。

针对不同场景,采用不同的关键字来表示循环访问,可能更加自然。实际上,while、until、loop和for range本来就是不同的需求。

小结:

循环语句三个方案:

  • 从。。。到。。。有。。。
  • 从()开始,到()为止,每次():
  • 不同的关键字表示不同的循环类型:每当直到遍历循环等。

分支语句

凹英文版的分支语句是:

switch i {
case 0:
    println("i is zero")
case 1:
    println("i is one")
default:
    println("i is unknown")
}

方案1. 凹中文版的原始设计如下:

当i:
    为0,则:
        打印:"i is zero"
    为1,则:
        打印:"i is one"
    否则:
        打印:"i is unknown"
。

这里的对应于switch对应于case则:对应于:否则对应于default之前的逗号是为了更清晰。

方案2. 用更白话的关键字,且用()包裹条件:

当i为:
    (0):
        打印:"i is zero"
    (1):
        打印:"i is one"
    ():
        打印:"i is unknown"
。

这个方案和上面条件语句的类match方案类似,也是更多地利用()符号。

缺点是如果分支语句中有带()的表达式,可能导致歧义。因此这个方案更适合与{}代码块配合:

当i为 {
    (0){
        打印:"i is zero"
        打印:"i is zero"
    }
    (1){
        打印:"i is one"
    }
    (){
        打印:"i is unknown"
    }
}

还有个缺点就是“含符号量”太高,读起来不够流畅。

小结:

分支语句两个方案:

  • 当。。。为。。。则:
  • 当。。。为:(){ }

建议将for循环的执行语句三放到最后会更符合中文语序

执行语句三原本就是会在循环完成后才执行

从x=0,到x>=10:
打印:x
。后x++

不加括号的时候变量名如果没有出现和关键字一样的字符还好

从甲=0,到甲>=10:
打印:甲
。后甲++

如果变量名出现和关键字一样的字符,就可能对可读性有一定影响,还会和关键字产生冲突

从到家=0,到到家>=10:
打印:到家
。后到家++

如果使用中文变量名,推荐使用括号语法

从(到家=0),到(到家>=10):
打印:到家
。后(到家++)