program-in-chinese / overview

中文编程的历史、现状和展望。issue 中进行相关问题的讨论.
https://zhuanlan.zhihu.com/codeInChinese
GNU General Public License v3.0
385 stars 34 forks source link

讨论: 适合中文用户的编程语言和IDE, 侧重于现有语言/IDE不具备的特性 #11

Open nobodxbodon opened 7 years ago

nobodxbodon commented 7 years ago

一个用户对象是中文为母语的开发者的编程语言以及配套开发环境, 应该有哪些特殊的功能, 才有存在的价值和维持开源的社区动力? 暂且不讨论如何实现的问题, 先搜集需求和探讨设计. 这个目标虽然是远期的, 但总要一步步实现, 希望这里能迈出第一步.

基于早先的讨论, 个人整理的一些如下. 视野有限, 仅作抛砖引玉:

开发环境
    集成语言源码(编译器,标准库等),方便用户修改/改进语言本身或丰富库,并方便验证修改对已有项目的影响. 理想情况是开发环境本身也能在自身中导入进行开发
    集成代码版本控制功能, 语言开发团队对语言/标准库与用户库/项目提供版本控制服务, 以提高团队开发效率, 促进共享, 提升整体代码水平
    提示/帮助文档贯穿整个开发过程
    集成语言解释器
    内置适合编程的中文输入法
    可以导入其他编程语言的项目
语言本身
    内置语法最简化, 可扩展性高. 想到的类似例子是Scheme/Lisp
    保证代码可读性的前提下优化性能/效率
    支持与其他编程语言的集成
    源码版本间易于比较
    易于理解的中文反馈信息, 包括编译错误/警告, 运行时错误等等

下面是参考易语言相关平台的官方文档,挑选出的一些. 本人没有易语言实践经验:

火山:
    支持中英文代码切换
易语言:
    代码即文档源程序风格统一
易语言飞扬:
    类自然语言编程 - 支持宏定义(和可扩展性高一致)
inkydragon commented 4 years ago

LingDong-/wenyan-lang: 文言文編程語言 A programming language for the ancient Chinese.

可以在这个的基础上试试去标点符号。

nobodxbodon commented 4 years ago

此文的评论区中指出:

比如最经典的 "abc".startsWith("a"),要在中文的思维方式里自然地表达出来就得使用「以」这个介词来连接两个对象。

如果这一点设计好了(比如 Z语言的序列式函数应用,比如 "abc"以("a")始()),绝对是不需要驼峰英文分词的。

否则的话 "abc".以始("a")或者好一点,"abc".开头为("a") 这种,那只能说是暴殄天物了,好歹也是所谓『夜鬼哭』的汉字啊。

由此想到(不确定是否之前讨论过),常见英文编程语言的方法命名都将参数全部置于方法名末尾,这也与英文特性有关,因为命名本身已经去掉了空格,如果拆分成几段的话就会比较别扭。以假想中的方法为例作中英对比(暂不讨论API 设计和语言实现问题):

startsWith("a")endsWith("b")
以("a")开始("b")结束

相对而言中文版更加接近自然语言用法。不知是否已有中文编程语言设计允许方法的参数在命名的非末尾位置出现,类似这样:

定义 以(开头)开始(结尾)结束 {
   ...
}

以几个常见编程语言的标准库中 api 为例作对比:

Java的Collections.replaceAll(List list, T oldVal, T newVal) 调用时:

replaceAll(列表, "aa", "bb")

一个问题是,在读代码时不能一目了然哪个是新值,哪个是旧值。 如果用中文命名,可以是:

用("bb")替换(列表)中的("aa")

刚看了下replace已经基本约定俗成为旧值在前,新值在后。但中文命名接近自然语言的优势仍在。

另外,英文api 的重载如何对应处理?比如Python 的replace,可指定最大替换个数:

str.replace(old, new[, max])

一种可能是添加从句(是这么叫吗?)

str.用("bb")替换("aa"),前(3)个

这里的方法定义就是用(新值)替换(旧值),前(n)个

另一种:str.用("bb")替换前(3)个("aa"),两种都不是简单重载,毕竟如果走接近自然语言风格的话,混搭比如用("bb")替换("aa", 3)会比较怪。

感觉把参数命名的意义相对弱化了。好处是 api 的用途更加一目了然,不用特地从文档查询各个参数的意义。

再来个参数巨多的例子。Python 图形库 tkinter的按钮,除了必需的所在容器,参数可设置前后背景、图片、高宽、文字、字体、可变文字等等十数个。

比如:

Button(搜索区, text="搜索", image=放大镜, command=搜索文本)

这种情况,似乎用多个从句比较合适(也易于命名和扩展):

(搜索区)按钮,文本为(“搜索”),使用图标(放大镜),调用(搜索文本)

这里又牵扯到类型强制转换,因为多数语言中(类A)对象是强制转换对象为 类A。而如果允许参数在命名的任何位置,包括开头,比如上面的(搜索区)新建按钮,那么类型转换就需要用其他语法。

类型转换用类A(对象)的话,与对象初始化语法一致,貌似也没什么问题(效果一样?)。更接近自然语言的可以是(对象)转为(类A)

【待续】

zj1d commented 4 years ago

另一种:str.用("bb")替换前(3)个("aa"),两种都不是简单重载,毕竟如果走接近自然语言风格的话,混搭比如用("bb")替换("aa", 3)会比较怪。

Glide.with(this).load(imageUri).into(imageView);

nobodxbodon commented 4 years ago

@zj1d 链式调用仍可以应用(它也有局限性吧)。允许参数在命名非结尾处感觉可以更加灵活地命名 API,尤其是多个参数的方法,比如indexOfSubList("st")在("test a")的位置会比较可读。

或者有些英文表达直译过来有些不符中文习惯的,比如removeIf,相比直译的移除如果(...)如果(...)移除更接近一些中文用法。

duangsuse commented 4 years ago

https://duangsuse-valid-projects.github.io/Share/绝句/绝句词法#解析器实现-kotlin-literate

你们先看看这个吧,我研究一下上面是啥 (从头开始看也行,不过上面链接引的那个 # tag 好像就没意义了) (总之慢慢的几天内绝句就会被形式化定义出来的,放心)

duangsuse commented 4 years ago

欸冰封怎么还在这呢

Screenshot_2020-01-01 讨论 适合中文用户的编程语言和IDE, 侧重于现有语言 IDE不具备的特性 · Issue #11 · program-in-chinese overview

给人感觉风马牛不及的……这是人间烟火啊 有点牛逼啊 :+1: ,我还以为没人能搞 :frog: 大新闻的

duangsuse commented 4 years ago

@zj1d 链式调用仍可以应用(它也有局限性吧)。允许参数在命名非结尾处感觉可以更加灵活地命名 API,尤其是多个参数的方法,比如indexOfSubList("st")在("test a")的位置会比较可读。

首先我觉得还是说几句:我觉得在语言都还没有定好的情况下是不应该太考虑API的,不是不应该考虑,但是语言……基础的定义、控制结构,已经确定,这必须是前提吧。

然后我还有几句,是之前我说过的:

以前我偶尔以『艺术品』的心态想到『用中文写程序』,把中文看得比编程重,结果写出来的东西不像中文更不能编程。

现在我多学习了几门『不常见』的编程语言,Haskell、Scala、Kotlin,结果写出来的东西不仅符合编程逻辑而且像中文,这真是奇怪啊。

如果你连文字都不会敲、逗号顿号傻傻分不清,是设计不出『中文编程语言』的,这一点不必多说吧。

其实它的意思是,有时候不能老盯着『中文编程』本身不放,你们看楼上的 ice1k 冰封哥,如果他想设计那做出来绝对比许多『中文编程语言』好看,因为那些人连都AVL树不会写。 😂

说点实际的,如果你没用 Haskell 写过程序或者用许多 不同的语言写过相同的程序,也不会觉得 Ruby、Lua、Julia 都在用的 end 有啥问题吧,绝大部分人,甚至少部分编程语言的实现者、以至于Pythoneer们……,居然不知道缩进可以用来蕴含 a(o1 o2 o3)b 这种嵌套信息,但 Haskell 程序员全都知道。unfortunately 许多 Haskell 程序员对『英文编程』或『中文编程』不敏感,他们懒得设计一门『中文编程语言』,所以我今天所看到全部的中文编程语言,都是不带布局的,这里我说的布局可以理解为Python的「:」。

之前我考虑过关于绝句逗号表示法的一些事情,我复制一些(因为这个东西我也是现在还在准备设计……也不算是真的设计完了,还有很多东西没看):

当然以下稿子,最终的结果我还要再修改(包括设计到现在很多残次语法已经删了、换了,没太大时效性)

https://t.me/dsuse/11778

[In reply to duangsuse::Echo] 简单的说,逗号文法就是这四种情况:

嵌套链「,」的右边只接受嵌套链或嵌套段。 若p0,若p1,若p2, 这一行() p0 p1 的收的都叫嵌套链,最后一个是嵌套段。

逗号取调链就是,在使用直接表达式作为块参数的时候,

比如说:宫水家.找,她:她的名字是"三叶"。手机上的最近聊天记录.数,它的发送者是泷。有若「大五十」 空则,抛下沃日("emmmm")。 唉,我看逗号块还是允许利用:指定默认的 it 吧,毕竟这是中文,把人称作「它」实在是太过分了…… 这一点不用中文编程还看不出来啊woc

控制流简记是针对表达式的情况,即便回/抛下/停下/略过是语句,它也可以取而代之, 对表达式组的最后一项也一样。

当然这些(后来再修改了以后的版本)很显然都是比较容易实现的,至少比我之前想的那个能多个 若, 之类共用一个句号,或者允许 对xss里的xs,对xs里的…… 的那种强多了。

然后你上面提到的『不符合表达习惯』按你举的例子如 users.removeIf(he -> he.is穷逼() || he.not小康()) (开个玩笑)翻译过来是 用户.除去若(他 => 他.是穷逼() || 他.不小康()) (我也是瞎翻译的),说白了就是语序不正,因为中文都是把上下文放前面,users.removeIfremoveIf 其实还应该放在 predicate 后面的,比如:用户“里”去删除「是穷逼或不小康」的人 (当然是伪代码)

duangsuse commented 4 years ago

另一种:str.用("bb")替换前(3)个("aa"),两种都不是简单重载,毕竟如果走接近自然语言风格的话,混搭比如用("bb")替换("aa", 3)会比较怪。

Glide.with(this).load(imageUri).into(imageView);

我想你是不是理解错了…… 那个 x.op1()op2() 不是说可以省略掉中间那个 .,那是绝句程序设计语言新加的语法特性,「记法」,类似Kotlin的 infix function 但不需要加空格…… 之所以有那种类似自然语言的表示方法,是因为绝句还有「内联物」和「扩物」(目前都是计划暂交由Kotlin编译器支持)。那种方法不是不可以,甚至我以前还有更奇妙的想法,比如弄个所谓的预处理器啥子的(其实我当时估计是连预处理器PCH, Precompile Header、Preprocessor具体处理阶段和有几个指令都不知道,虽然我不是打算要写C预处理器……)

https://t.me/dsuse/10123

[In reply to duangsuse::Echo] 待会继续说『绝句』的,我一定要先实现这个玩意... (虽然可能不如 parser 们更优雅,因为虽然它是完整的模板语言,也有被当成 CPP 这种『逐行处理』的风险... 汗)

先一言不合就念诗:

int main() {
  ~绝句 (https://www.gushiwen.org/GuShiWen_97f95d9179.aspx)~
  [唐] 杜甫
『两』个『黄鹂』;鸣『翠柳』
『一』行『白鹭』... 上『青天』
『窗』含『西岭;『千』秋『雪』』
『门』泊『东吴』。『万』里『船』
}

说这玩意是代码你们相信么? 如果这执行玩意可以打印出下面这种东西,你们相信么?

🌴🦜🦜🎵 🐦🐦🐦🐦👆🌥 🏠👅西岭📆1000years:❄️ 🚪🅿️东吴🚢🚢🚢🚢9997km

🤔???

这是今年4月28 的事情

然后 Glide.with 的那种方法我之前也考虑过,甚至我到上上个星期为止都一直是这么想的,如果你们用有 extension function 的 Kotlin 很快就能把这种思路扩展到一个可以工程实用的级别,它翻译过来大概是

Glide以(此物)加载(图像链接)至(图片视图)

其中用到的DSL方法就是 ,主要就是这个,其它的可以写在多态返回类型里嘛(比如可以「以」图像设置啥玩意、「以」Http客户端加载图像……)

duangsuse commented 4 years ago

https://t.me/dsuse/12099

引记法 绝句.额联 「令为」
引记法 绝句.符号 「以」
引记法 绝句.符号 「~个」
引记法 绝句.符号 「化」

引 Apache.PortableRuntime

例 随机生成: App 为“皮一下,标准库里不一定有这个别名,当然绝句也可以用上「类物别名」的”
  实现的事 入口() 为
    说("请输入将要生成的随机数个数:")
    量 数目 = 听去数一()
    说("下面开始生成${数目}个随机数====>")
    随机数之集去取(数目个) 令为,它以(" ")去接并()。令为(::说)
    说("<========随机数已生成")
    听去行一() “暂停屏幕滚动用”

例 随机数之集:随机数集()
物 随机数集 为 “也可以是单例的”
  私下、晚成的“lateinit”变参 存池:内存池
  事 取(次:数目):行<数> 为
    存池 = 内存池()
    量 随机行:行<数> = 行一()
    解对 次里的_,随机行去加入(随便一数())。
    回随机行     
  私下的事 随便一数():数
  = 随机数器去生成随机数(1、分配器=存池)
  去化数()

不是那种毫无规则的简化,设计是相当克制的

还可以看看

https://t.me/dsuse/11812

duangsuse commented 4 years ago

顺便说一句,

用("bb")替换(列表)中的("aa")

这种用法其实 Kotlin 里就已经可以实现了,甚至可以说是完美地实现。不过绝句的目标显然不可能只是这个。

//定义一个上面的 fun 可以多态的类型,当然此类型可以定义为内联的
//类型参数在取值的位置是自动推导的
data class 用<某值>(val 某物: 某值)
data class 位置和源<地, 某值>(val 位置: 地, val 源: 某值)

infix fun <某值> 用<某值>.替换(位置: MutableList<某值>) = 位置和源(位置, 某物)
infix fun <某值> 位置和源<MutableList<某值>, 某值>.中的(目标: 某值) = 位置.replaceAll { if (it==源) 目标 else it }

// 介于Kotlin貌似为了理论优雅?没这个方法,而且Collection貌似是不可随机访问的
//fun <E> MutableListE>.replaceAll(origin: E, replacement: E) {
//  for ((index, x) in withIndex()) if (x == origin) this[index] = replacement
//}

//算了是这个意思

fun 入口() {
  val 列表 = mutableListOf(1,2,3)
  用(0)替换(列表)中的(3)
  println(列表)
}

你们也看到了 Kotlin parses these code,所以理论上是可行的,至于为啥不能用是因为我不熟悉这API而且熬太晚了

所以我才说,如果我直到上上个星期还保留着的思路用于编程实践是绝对没问题的,至于为什么这样的API还没出现那就不知道喽。

没想到吧?俄罗斯人写的Kotlin用来『中文编程』反而比『中文编程』易语言更贴切。编程到了一定境界所有语言都是互通的,而且甚至不止是过程式、面向对象、函数式 hello, declarative world

nobodxbodon commented 4 years ago

@duangsuse 不好意思,可惜不大会 kotlin。关于用("bb")替换前(3)个("aa")这样的语法,之前只是想在现在大多数语言的方法定义(仅支持参数位于末尾)的基础上作一个改变(进?),与其这样定义:

def replace(old, new, max):
    ...

允许这样定义(暂不讨论关键字):

def 用(new)替换前(max)个(old):
    ...

(无意尽量避免括号等)

我觉得在语言都还没有定好的情况下是不应该太考虑API的,不是不应该考虑,但是语言……基础的定义、控制结构,已经确定,这必须是前提吧。

个人(只学过一点 PL 皮毛)觉得 api 的设计(比如上面的语法改变)会影响语言本身设计。而且也许有时牵一发动多处,比如楼上末尾牵涉到类型转换,等等。英文 api 已经基本约定俗成了所有参数在方法最后声明,因此这方面并无什么发挥空间。

如果,支持上面的方法定义用(new)替换前(max)个(old),以及如果(...)xx这样的方法命名,代码写出来也许是这样的:

文字 问好 = "你好"
数[] 号码 = [1, 2, 3, 4, 5]

问好 = 问好.用("吃了么")替换("好")
号码.如果((数) -> 数 > 4)移除

对(号码)中的(某数) {           // 遍历这样看起来有点像是方法调用
  说(问好 + 文字(某数))      // 假定强制转换必须显式

  如果(某数 % 2 == 1) {         // 与`如果()xx`方法看起来有点像
    ...
  }
}

写出来之后会发现更多问题(个人短期内无打算深入)

之前写过一点关于语言设计和 api 的顺序,现在仍觉得,如果首先从语言设计(甚至实现)出发,往往会出现削足适履的情况。越早编写接近实用的例程,越能发现语言设计的缺漏和可优化之处。因为实用(尤其是与实际业务相关的,而非纯算法)代码将是语言推广后存量比例最大的。而接近实用意味着至少是一小部分api 设计,以及一定的标识符命名风格。

楼上的例程,个人(也许对目标人群有不同设想)第一眼感觉,“听去数一”,“解对”,“去化数”, “次里的”等等难以一目了然。另外,逗号、分号、句号、双冒号、顿号、波浪号等等似乎都是语法因素,也许会增加学习和使用负担。

语言设计时,相信忍不住会逐渐加入更多更强大的特性,期间需要不断把中文特性这个“足”塞到这些特性组成的越来越小的“履”中。几乎无法避免地,会导致包含这些特性的例程的可读性的下降(也许可写性也是)。更大的问题是,由于语言设计者自身的视角问题,往往不会觉得这种可读性的牺牲是什么问题,因为设计者本身是对特性最熟悉的人(甚至比其他使用的编程语言更熟悉)。即使对路人非常难读的代码(由于对语言特性不了解,以及试图用老思维理解新事物的本能),对语言设计者来说却是轻车熟路。

因此,个人认为,为了避免上述情况,最好是尽量一开始就从尽可能接近实用的例程出发,反过来决定 api 和语言设计。这样,至少一开始能够尽量从最终用户的视角检视例程(在真正开始设计、实现语法之前,尽量确保程序对于新手来说是“好用好懂的”)。即使在之后由于各种设计或实现原因需要改变例程,至少有个参照和基准,也不会太轻易地牺牲可读性。这也和一般项目在设计之前,在获取需求的早期尽量搜集有代表性的 user story 的思路相同。

duangsuse commented 4 years ago

呃我就照着你说的一段段回复吧:

@duangsuse 不好意思,可惜不大会 kotlin。关于用("bb")替换前(3)个("aa")这样的语法,之前只是想在现在大多数语言的方法定义(仅支持参数位于末尾)的基础上作一个改变(进?),与其这样定义:

(写完本回复我又看了一下,之前那个KotlinFriceEngineDSL的封装嘛,我觉得不是很理想。) 比方说(我这里不改变命名的大含义),应该用 左上角 = 点(x, y) 的形式弄,比把两个同类动作写在两行强(或许第一次写你觉得省脑子,重写、多写点,你就会抱怨它多余了),而这只需 typealias 点<A, B> = Pair<A, B> 然后加个扩展函数即可实现。实际上这是很平常的抽提(抽象、逻辑提取)思路。 而且 加速度_左负右正写的时候觉得是中文比英文好的一点,因为它更明确 我很同意,可任何事物都有两面性。 我在写程序的时候也经常要问自己一个问题——某个重复逻辑值不值得我提出来?在Kotlin里很多时候我的回答都是「是」,但这不代表不需要问这个问题——抽象也可能给别人的理解和阅读制造难度(Java里尤其明显),而命名上过度的注释也可能给别人的使用造成难度 e.g. setPositiveSizeLimit 的 'positive' 是否应该写在名字里?况且物理上加速度方向取数论的正负数符号,这是有理论优雅性的,无须再重复强调许多遍(即便要强调也不该被完全表示在仅此属性的命名上)。

def replace(old, new, max):
    ...

我的观点:这绝对不能算作是改进,尽管它往往不会与绝大部分语言的原文法冲突也不能。(JavaScript在限制不换行的情况下也不会)

就实现可能性上,一般我们认为 someFunc(a0)aname1(a1)... 这样的模式,当然是可能与绝大部分只需要 一个参数(但不至于与需要一个 tuple 的函数)相冲突的(我是指对于老思路那些 不需要 这种特性定义的函数)

但是,如果文法上直接换成这种形式定义,其实也没什么问题(看刚才我写那Kotlin就知道的确是没啥问题,因为按Kotlin语法 f() 完后的后继只能是中缀. + 或另一个前面肯定没名字的后缀如 ()、看Z语言也知道的确是没问题)。

首先我相信绝大部分静态类型检查的编程语言设计者,尤其是重视代码一致性的程序员都讨厌一些比较容易混淆的语法,尽管也有许多人喜欢 Ruby、Python 的 "keyword arguments" def dig_a_hole(depth: 1, label: 'hole'); puts"$label $depth"; end 这种。

包括我之前在 以绝句语言翻译 你之前翻译那个 Swift 的时候我都这么想,如果参数列表可以随便hack成那样:

func 问好(_ 人: String, 在 日子: String) -> String {
    return "吃了么\(人), 今天是\(日子)."
}
问好("小黑", 在: "周三")

如果没学过,哪怕是作为一个初学者你能明白这TMD是在做什么吗?下划线是什么意思?『日子』和『在』有啥联系?还是区别?反正我是看不懂。

介于我之前发了很多 t.me 的链接估计都没人点进去看,我摘一点吊吊胃口

“func 统计(得分: [Int]) -> (最小: Int, 最大: Int, 总和: Int) {
    var 最小 = 得分[0]
    var 最大 = 得分[0]
    var 总和 = 0

    for 分 in 得分 {
        if 分 > 最大 {
            最大 = 分
        } else if 分 < 最小 {
            最小 = 分
        }
        总和 += 分
    }

    return (最小, 最大, 总和)
}
let 结果 = 统计(得分: [5, 3, 100, 3, 9])
print(结果.总和)
print(结果.2)”

“绝句里单引号是文档,可以在工具里看到。”
“一个类/物的类型参数可以直接加入文档,参数和返回值的文档可以直接加在前面也可以独立加”
“和Kotlin,也是Markdown的”
事 统计(得分:组<数>):‘最小、最大、总和’ 元三<数、数、数> 为
  对得分里的分,
    判分, “一时间我也找不到更好的方法把「对」和「判」连在一起”
      它大最大,最大 = 它。 “「它」是此分支局部的”
      它小最小,最小 = 它。
      否则,效果。
      上皆,总和令置为「+分」。
  回元三(最小、最大、总和)
这里,
  变数 最小 初0;变数 最大 初0;变数 总和 初0 “不是一般的编程风格,但不置可否。”
  “这个版本里,暂时我不会把对「变(属)(名)初(言)」的修改加上,请兼容前面的一部分。”

我觉得这样的语言对所有,甚至包括 mother tongue 是 English 的人都是莫名其妙的,而且类似的语言不在少数。

这就是一个观点的问题,也就是『脚本化』还是『规范化』两个互斥的方向,可能相关的你可以看看冰封哥的 形式验证、依赖类型与动态类型

拿一个最简单的例子:比较 Bash 和 Python 当然其实 Bash 作为一门 Shell 语言也是有『形式化』(除了heredoc字符串语法)的语法定义的。 可它的可读性、易学性真的不能与Python相比,或许你会说它们根本不一样,但 Bash 的确是程序设计语言,不过没 cshelvish Shell 那么明显而已

比方说呢?Bash 的函数不能有形式化参数,只能在函数体里 $1 $2 $3 引用,而整个脚本居然也能把 shell 的参数以 $0 $1 $2 引,好像 bash 命令是个函数一样、尽管有作用域,函数里定义的变量默认是全局作用域还需要 local 来定义一个「局部的」、尽管函数带括号,调用都是 f x y 这种形式,而且三种引号 '' "" \`给人感觉简直难以区分、file pattern 的直接裸写有效也让人经常在参数里包含一些特殊字符时遭逢莫名其妙的问题,更别提|`> < 符甚至 2> 2&> <&- n<&- 这样看了文档也好长时间才能记住的『重定向』,以及莫名其妙的 +-*/ && || declare 和所谓的 [] test 这种加不加空格都有区别还有 N 种写法的『命令』了。

再比较Python和Java,就不提属于运行时特性的 eval 了(而且 Java 也完全可以利用 compiler API 或者 ClassLoader defineClass 动态编译加载到虚拟机来执行代码),不知道有没有Python能吐槽Java的某一点 介于 Java 1.7 都有 try-with-resources 了,他们没法吹 Python 的 with 这种“更自然”的 try-with(当然 Kotin 可以光明正大地藐视所有这样的『脚本语言』,因为它的标准库里一个 use 函数就定义了这个被Python视为『语法』的东西,而你甚至不需要知道那个语法是 with res as name:,IDEA 里 Ctrl-Q 一下就能立刻用上)(原来绝句也有 尝试文件去开()成某书……,这么一写我觉得不能有了)

我想他们要吹的肯定是 Python 的动态类型、duck typing,这样你就可以随性地使用任何有 size 属性的对象上的 size 来取长了,而 Java 不仅每次写 Something something = new Something(); 麻烦还要各种写 Adapter boilerplate 来解决这种问题,Oh yes my dear Python。

我就不吐槽 Python 那毫无规章的『元方法』如 lenrepr 和莫名其妙的『面向对象』设计以及基础库了,Ruby程序员一直在吐槽。 它的 : layout 式语法算是一种创新,可仅止于此,其他的设计都是极度三八极度脚本化的,简直恨不能为Bash,想想Python3都忍不住跨大版本都快抛弃向前兼容了还没改过来,我真是极度地感到惋惜。

例如Kotlin这样的语言更不可能看上这种语法,因为它可能与 infix fun 存在语义上的冲突,即便这种冲突可以解决但那可能会给语言的使用者制造一些问题(比如,随性定义了一个使用常见介词的函数,结果与其它函数库的版本冲突……实践上这尽管能解决但不该有这种问题)

至于如果一定要说静态类型的好处,其实封装、抽象、继承、多态、fail-fast 我就不用说了,引用冰封哥的一句话(貌似是,忘记从哪看的了):

一个多态就能吊打它们了

没错,一个参数类型式的多态就比它们强太多了,不论类型是否一定要显示标明,静态类型都能在更早的时候确定更多的信息(不需要很复杂的推导算法),基于这样的信息你可以无开销地弄出许多DSL和针对特定输入的优化版本程序,或者仅仅只是静态的 optional arguments 也很好。

我的另一个观点是,一门好的编程语言不应该能让它的使用者写出不好的代码,哪怕只是可能。

允许这样定义(暂不讨论关键字):

def 用(new)替换前(max)个(old):
    ...

(无意尽量避免括号等)

貌似无论是 Python 还是 Ruby 上这种修改都没有太大问题,不过 optional arguments 和 keyword arguments 就不应该在这种形式支持了,如果更严格我觉得使用这种形式的 Python/Ruby 就不该有 optional/keyword 了,而且 Ruby 的 &op 块参数也要好好考虑怎么弄好。

def call_with_1p(n, &op); yield(1+n); end
call_with_1p(0) { |x| puts x }

不过介于 Ruby 其实已经支持这种形式(出于它有 f a b 这种无论是我还是 Haskell 大佬看了都会绝得自己酸死的 Bash 式语法) 不过要写出来是比较麻烦的,类似 trie 树地,它要判断自己的参数是不是对象 替换前 后面的后面(就是下一个参数)又是不是 什么的,比较麻烦。

但如果你觉得 用(new)替换前(max)个(old) 可以实现为 Keyword arguments 的形式(它在定义里表达原 用(x, 替换前: max, 个: old) 使用参上),我觉得相对比较好实现,不过我显然不能帮你实现(还有绝句解析器要写啊)

我觉得在语言都还没有定好的情况下是不应该太考虑API的,不是不应该考虑,但是语言……基础的定义、控制结构,已经确定,这必须是前提吧。

个人(只学过一点 PL 皮毛)觉得 api 的设计(比如上面的语法改变)会影响语言本身设计。而且也许有时牵一发动多处,比如楼上末尾牵涉到类型转换,等等。英文 api 已经基本约定俗成了所有参数在方法最后声明,因此这方面并无什么发挥空间。

是的啊,所以我刚才没说得太绝对,我自己也深有体会,比如写这个回答的时候就因为提及了Kotlin标准库的一个设计,我决定改掉一个语法,之前我以绝句重写了某JavaScript ES6的代码后我又改了绝句的一个「构词」。

而且说点不相干的,你个人研究中文编程也有几年了吧,我能给最大的建议就是:多『学』几门语言,好好斟酌比较一下它们的区别(这是别的方法无法替代的),总结出点类似「顺序、判断、重复」这样的东西来,也不必学多高大上写 LLVM 编译器前端 IRBuilder、JIT 什么的,就琢磨一下语言的设计就挺好。

如果,支持上面的方法定义用(new)替换前(max)个(old),以及如果(...)xx这样的方法命名,代码写出来也许是这样的:

文字 问好 = "你好"
数[] 号码 = [1, 2, 3, 4, 5]

问好 = 问好.用("吃了么")替换("好")
号码.如果((数) -> 数 > 4)移除

对(号码)中的(某数) {           // 遍历这样看起来有点像是方法调用
  说(问好 + 文字(某数))      // 假定强制转换必须显式

  如果(某数 % 2 == 1) {         // 与`如果()xx`方法看起来有点像
    ...
  }
}

写出来之后会发现更多问题(个人短期内无打算深入)

呃这样我没啥可说的,我贴一个自己之前写的代码(当然也有很多在我的笔记上没发),以及一个以目前绝句设计能有效的代码吧

把(这人.的(朋友们).中(所有(名字.以("abc").起始().的()))).都拿去(用户表::删掉);

从(1).数到(100, (它) -> {
  若((它/2).为零(), 向(终端).写("偶数"))
  .否则(向(终端).写("奇数"));
});

Consumer<?> 不可能 = (Object _) -> { throw new ImpossibleException(); };
判断(他.的(名字),
  倘若(它.是("蔡徐鲲"), 向(它).致敬()),
  倘若(它.是(在(iKun.映射到(IKun::名字)).中()), 向(终端)::写),
  否则(不可能));
判他的名字,
  是"蔡徐鲲",我致敬(它)
  在 iKun映至「的名字」“其实不该每次去投至”,输出写它
  否则,不可能。
引记法 绝句.严格中文 「以」
引记法 绝句.集合 「滤」

变文 问好 初 "你好"

“「初」不是随便设计的,我有其它考虑这里不提”
“如果是常量可以用「常文」或「量」”
“ 量 问好:文 = "你好" ”

量 号码 = 动组一(1、2、3、4、5)
“Mutable Array (而非 Array<out T> 那种,类型系统一样但提供了一个简写法)”
“ inline fun <reified T> im(vararg items: T): Array<out T> = arrayOf(*items) ”

“绝句不支持一至九开头是因为数字也可用它们表示,”
“这也不是随便设计的。”

“介于绝句不是『脚本语言』以及例子的完整性”
事 入口() 为
  问好 = 问好去置换("好"到"吃了么")
  “量 某表 = 表一("天"到"地"、"海"到"空"、"大陆"到"长空")”
  “解对(1至10)与(1止11)里的(甲、乙),断言(甲是乙)”
“这是一般用法,「对」是存于 绝句.额联 的中缀记法”
  问好 = 问好以("么?")去置换("么")
“这是「记法」的用法,当然也可以显示用「去以」而不省略访问符”
“你上面的代码好像写错了,暂且把『移除』当成 "xs[i] = null" 处理吧”
  对号码的索引里的针,
    若号码[针]大4,号码[针]=空。
“这是绝句第一版的风格,和Kotlin差不多;到时候有了 `存储<值者>` 抽象就不一样了”
“我们也可以用函数式的风格,但这里一般风格更好,尤其是现阶段绝句没任何优化靠Kotlin的情况”
  对号码滤出不空里的,
    说("${问好}${它去化文()}") “去化文也不必写”
    若它之为奇数,效果“啥都不做”。

扩物 数 为
  记法「之」的量 之为奇数 取者,我取取余(2)是1。 “我又决定绝句要去掉 % 中缀符转用记法了”

之前写过一点关于语言设计和 api 的顺序,现在仍觉得,如果首先从语言设计(甚至实现)出发,往往会出现削足适履的情况。越早编写接近实用的例程,越能发现语言设计的缺漏和可优化之处。因为实用(尤其是与实际业务相关的,而非纯算法)代码将是语言推广后存量比例最大的。而接近实用意味着至少是一小部分api 设计,以及一定的标识符命名风格。

所以你要写啊,尽管许多语言的入门示例足够概况,但那远远不够啊。

楼上的例程,个人(也许对目标人群有不同设想)第一眼感觉,“听去数一”,“解对”,“去化数”, “次里的”等等难以一目了然。另外,逗号、分号、句号、双冒号、顿号、波浪号等等似乎都是语法因素,也许会增加学习和使用负担。

其中 听去数一,其实我也很没办法,毕竟为了语言的一致性「去」访问符根本无法省略、解对 是我刻意那么弄的,本来也可以遵循Kotlin仍用 ,它就是来描述 for ((index, item) in list) 的这种。

此外「次里的」是你理解错了(因为绝句是期望不带空格的风格的),其实它是 对(n次)里的 的意思,这里用「解对」的确是令人困惑,但你同时去掉「解」和后面的「_」后它依然是工作的,逗号后面的 body 里多一个叫「它」的变量而已。

知道「去」是 . 的意思你就知道 听去数一 其实是访问 对象上的 数一 方法了,在 Java 里这是 input.nextInt()去化数 则是 toInt() 的意思。

逗号、分号、句号、双冒号、顿号、波浪号都是语法因素

所以说才叫『中文编程』啊,你试试就会知道只要输入法质量过关,没有任何问题。

『某』 为可不带空格的『角括名字』、「某」 为中缀表示、【某文形】 为标记修饰、〖某文形〗 为块参数列表

https://duangsuse-valid-projects.github.io/Share/绝句/绝句词法

学任何语言都是要学这些表达形式的,我在设计时刻意没看Kotlin的词法规则,就是为了能设计出更贴切中文的文法表达。

语言设计时,相信忍不住会逐渐加入更多更强大的特性,期间需要不断把中文特性这个“足”塞到这些特性组成的越来越小的“履”中。几乎无法避免地,会导致包含这些特性的例程的可读性的下降(也许可写性也是)。更大的问题是,由于语言设计者自身的视角问题,往往不会觉得这种可读性的牺牲是什么问题,因为设计者本身是对特性最熟悉的人(甚至比其他使用的编程语言更熟悉)。即使对路人非常难读的代码(由于对语言特性不了解,以及试图用老思维理解新事物的本能),对语言设计者来说却是轻车熟路。

这么说吧,其实也不无道理,但我对绝句的看法是,既然它也不是特别困难而且我现在也只需要上好学,我不要他们以为、我只要我以为。

期间需要不断把中文特性这个“足”塞到这些特性组成的越来越小的“履”中。

为什么不试试以「中文」这个食材,煮盆「程序设计语言」的汤呢?我刚才说了,中文的语序是上下文如目标对象在前、关键描述在后。所以『中文编程』实际上是指『编程』,但它的前提是『以中文』;而不是『以编程』去倒贴『中文』。『中文编程』既要有『中文』更要有『编程』,只有比重视中文更重视编程的人,才有能力设计出好的『中文编程』语言。

中文它不是一种特性,而是对编程本身的描述手段,不应该说『为了让中文兼容某某语言特性』而怎么样,而是那些语言特性,必须变得适合中文,或者说被『削』的不是中文而是特性,这就要求设计者有相当的编程功底,以至于能够对每个『不合适』的特性有所斟酌取舍。

因为设计者本身是对特性最熟悉的人(甚至比其他使用的编程语言更熟悉) 我觉得这一点是非常有必要的,那个「甚至」我觉得对任何好一点的编程语言来说 都是最基本的要求,如果一个程序设计语言的设计者无法默写下它的文法,甚至只是不能以那门语言「实现」那门语言本身,那他也不配当那门语言的设计者、那语言也不是好语言。

因此,个人认为,为了避免上述情况,最好是尽量一开始就从尽可能接近实用的例程出发,反过来决定 api 和语言设计。这样,至少一开始能够尽量从最终用户的视角检视例程(在真正开始设计、实现语法之前,尽量确保程序对于新手来说是“好用好懂的”)。即使在之后由于各种设计或实现原因需要改变例程,至少有个参照和基准,也不会太轻易地牺牲可读性。这也和一般项目在设计之前,在获取需求的早期尽量搜集有代表性的 user story 的思路相同。

这也和一般项目在设计之前,在获取需求的早期尽量搜集有代表性的 user story 的思路相同。

这是现在工程界普遍的看法,我对它其实是中立态度,不过我也有其他的看法

看完之前你可能很好奇我为什么是这么想的。 即便我的数学很差,我还是觉得我有这种『在设计时能够看到使用处』的天分,所以我能在即便是核心库、标准库还未确定的情况下就开始设计语法、定特性,上文的 Kotlin Literate 部分也是一个佐证——不知道一些抽象类怎么用的时候你是没法好好定义它的。

如果你多往下翻几页,点那个 啥啥code 的按钮,就会发现那代码复制下来直接可以写进Kotlin文件编译,而我写完后也只是改了一遍修了两个非逻辑错误就编译通过了。

程序设计 本身 ,不是所有人都在说的所谓 优雅 的代码、不是看某某人的博客,也不是对有图形用户界面的应用做最优秀的界面交互设计。

刚入门的程序员扣老师枚举出的语法,战战兢兢地拿那一堆惯用法组织自己的逻辑、加入实际项目的工程师扣刻板复制的项目管理、设计模式、代码风格,

可是真正的程序设计大师 只扣 对编程的 直觉 和程序 本身的灵魂 , 对他们来说已经没有入门者的条条框框、刻板的约束了,回归初心,他们看到的是 程序所做的事情本身 , 是程序的灵魂;换十种兼容的语言和底层抽象去描述也不是问题,因为他们已经站得足够高,无须顾虑脚下低处的迷雾笼罩而可以自由地放飞视线, 不识庐山真面目,只缘身在此山

人类的本质是复读机,可是有些人就是能在不断复读的过程中领悟到所复读内容的真谛,有些人最终也只能是记忆容量大一点的复读机而已。

语法本身是你对高级程序设计语言使用的基础,项目管理和那群系统管理员做的工作一样容易令人困惑,必须强记。模式是容易复制却又很少被彻底看懂 看透 的、代码风格可以被机械化的解析、模式匹配、自然语言字典分词、自动却又很 刻板 地检查整理。

优秀的程序员 授人渔而不是授人鱼 ,看懂某个模式、弄懂某个框架或者库、语言特性、开发工具的使用,熟悉某种基本模型,是的,都很好。 但是 学一就只能得一,做不到举一反三 、用归用 忘还是会忘 ,并且既得知识非常容易失去 因为学到的浅层知识 根本没有产生联系不能做到融会贯通 ,甚至刚用完就忘者不在少数。

当然,看起来工程本来就应该是这样, 理论是知道为什么但是它不好用,实践是它好用但不知道为什么。

duangsuse commented 4 years ago

当然,看起来工程本来就应该是这样, 理论是知道为什么但是它不好用,实践是它好用但不知道为什么。

Kotlin是理论和实践的完美结合,所以,用Kotlin吧!

你们有福见到 ice1000 还没被骂还真是走运,现在人家在 Telegram 直播独立重写 Agda 编译系统的呢(Agda 仅就 mixfix 这一点看『语法灵活性』早完爆 Ruby、Python、Groovy 这种了,还不谈各种 where 布局非布局切换,虽然对 Agda 和 Scala 仅谈语法都是对它们的侮辱),我之前在没写过 Haskell 的情况下盲从王垠跟着骂基Lambda演算Haskell Type System结果被踢了(那时候我连 GADT 都不知道,更不知道还能 DataKinds、TypeFamilies……)。

duangsuse commented 4 years ago

你们弄的那个 项目们 还真是挺有趣的,之前没听说过那还可以那么写

这个圈三如果以后能让绝句以库的形式使用的话,那我觉得它的例程应该是这样

引记法 海龟 「~步」
引记法 海龟 「~度」

例 重复圈:海龟.图() 为
  事 画此图() 为
    计次(20),
      计次(360),
        前进(2步);左转(1度)
      左转(18度)

https://github.com/program-in-chinese/CoCaml#compiler 这个也不错啊,OCaML 毕竟是 CaML 好像 Haskell 的,也有「为……」

可惜我对几何的图形思维能力太差,根本算不出海龟的位置,根本不知道这能怎么简化

另,

http://www.chinesepython.org/ 的作者也提到了,布局文法对中文编程非常重要,这一点你们上面可能没注意到。(当然这完全不怪你们,因为只在写解析器的时候设计语言,而不能在语言还未具体定义的时候用它写许多程序的话,很难注意到居然有这种做法)

此外,ANTLR 至 v4 都是不可能直接在 grammar 层面实现布局文法的(但是可以在外部lexer里转化成隐含的类{}token,具体找ice1000的中文blog),这也是 Grammars-v4 里没 Haskell 的语法定义的原因之一。(另外的重要原因是 Haskell 的语言,偶尔带扩展现在已经有 100+ 了要支持也支持不过来啊……)

上面 ANTLR至v4、的「至」在绝句里是中缀符 .. 或者引用严格中文直接用「至」;还有「止」是 Kotlin 里 until 的意思,right-exclusive,『ANTLR止v4不支持……』听起来很自然吧?这是绝句在布局文法外支持最重要的语言特性——记法

  1. 為什么不做 中文Ruby, 中文Perl, 中文PHP ? 這和 Python 的編程格式有很大關系。 Python 的程式是用縮排來分段的, 因此沒有了花括號 '{}', 這令程式碼符合日常語的寫作習慣, 加入了中文后程式一樣簡單易明。 因為中蟒的主要目的是教學用, 清楚的句法要比速度, 面向對象的純正度, 程式表達的密度等都來的重要。 光是這點就否決 Perl/C/Java/PHP/.... 等一大堆語言。 我本人特別不喜歡 Perl 的那种拼命用特殊標點符號作為程式暗號的做法, 這樣只會嚇坏了我們一群天真無邪的菜鳥們。

上文作者唯一没注意到的是,缩进带语义并非 Python 的专利,Haskell、Agda、CaML 都有,所以绝句也有,不过使用了「逗号表示法」「为……」「其中……」的规范化形式。

duangsuse commented 4 years ago

@zj1d 链式调用仍可以应用(它也有局限性吧)。允许参数在命名非结尾处感觉可以更加灵活地命名 API,尤其是多个参数的方法,比如indexOfSubList("st")在("test a")的位置会比较可读。

或者有些英文表达直译过来有些不符中文习惯的,比如removeIf,相比直译的移除如果(...)如果(...)移除更接近一些中文用法。

所以说 某表.除去(它 -> 不能用(它)) 也行啊,不要忘了那句戒言:『只有问题必须设计新语言解决,才设计新语言』,不然会很麻烦的,那就和实践无关而归于艺术范畴了。在我看来这和『Industrial Haskell』一样令人感到奇怪。

编程是解决问题,不是制造问题。真正制造问题的学院派编程,他们制造问题的复杂度真是比那些把简单问题弄复杂的人造的复杂一万倍,小巫见大巫了。

duangsuse commented 4 years ago

https://wenku.baidu.com/view/d4424def4afe04a1b071de17.html

这篇论文真是废话满篇。对 踌躇踌躇志满 的区分要么然认为是『第一级解析』上要么然认为是『第二级解析』,这种东西还能先分成 踌躇、志满,应该是一次弄完的,我也是第一次听说有个词叫『志满』。

这人大概是自然语言学者,不是编程学者,尽说些没用的。全篇我没见他贴半点有效的代码,尽是写 natural language 的 statement,还都是那种无论对计算机作为一种 solver 还是对编程本身都表义不明的。

全篇什么作用域、指针、冯·诺伊曼、文法推导处理过程,全都是拼接一样极端不全、侧偏的定义,我肯定这人是第一次写这种论文,要不然他不至于连一点整理都不会做,是啊,说的都对,有什么用?能拿来编程吗?做不做工程是不一样的,那些只看着什么中文编程中文编程的人怎么会考虑中文真正写出来项目的易读性、复用性、可移植性、健壮性、安全性?排除了编程的『中文编程』就是个笑话。

duangsuse commented 4 years ago

……都支持utf8命名吧.

说真的看到你们上面举出的一些代码我都好绝望啊,难得你们对『用中文编程』那么热情还坚持了两年,可最终还是没一个能出来做工程的,不知道最近那个文言文能不能,虽然很有创意而且作者的确有两把刷子但我不感抱太大期望。

我实在是不想评价上面那个易语言式例子了,作者现在还在『中文编程』领域工作,也算是将功赎罪吧。

不提模棱两可的『变量初始化』问题,首先缩进就不明确,然后『无返回』,其实翻译成现代一点的编程语言都是 Nothingnever__Noreturn 的意思吧(所以按易语言的编程范式,叫『无值』其实都是可接受的),也不动脑子想想还直接 函数 无返回 某操无返回 某操函数 某操(): 无返回 都好啊!

例 某游戏:游戏() 为
  量 图片 = 精灵()
  实现的事 入口() 为
    图片去载入(":img/a.png")
    图片去定位(x=100、y=200)
    加入(图片)
    你图片,色罩=色元三(255、255、255)、透明度=1.0。
  实现的事 更新(间隔:数) 为
    待写

另,UTF-8 是 Unicode 文本编码的方式,请把字符集和编码方式区分开。此处应为 支持Unicode命名。提出这个说法的同学请好好学习一下 《其实你并不懂 Unicode》 以及C数据类型、甚至位长度及二进制编码相关知识…… @nobodxbodon

nobodxbodon commented 4 years ago

@duangsuse 很可惜近期很难学习实验编程语言设计了。 仍然觉得这个特性(允许参数在方法非末尾声明)值得摸索(有机会的话也想试试 Z 语言)。 更广泛的讨论仍然欢迎。限于个人对 PL 的知识所限,恐怕对你的见解还需时间细细领会。

另外,组内仍有对现有语言汉化的努力。 个人从2018年初开始基本转向对中文命名(包括 api)的探索。

duangsuse commented 4 years ago

@duangsuse 很可惜近期很难学习实验编程语言设计了。 仍然觉得这个特性(允许参数在方法非末尾声明)值得摸索(有机会的话也想试试 Z 语言)。 更广泛的讨论仍然欢迎。限于个人对 PL 的知识所限,恐怕对你的见解还需时间细细领会。

另外,组内仍有对现有语言汉化的努力。 个人从2018年初开始基本转向对中文命名(包括 api)的探索。

没关系,慢慢来嘛。反正也才快一年,我也会继续想办法实现我设计的程序设计语言的。 坦白说要给那么多语言设计汉化也很累,毕竟别人设计的语言还是蛮多的。

duangsuse commented 4 years ago

很多人提到易语言,因为他算得上中文编程中的成功者,但是实际上因为是纯技术出身,而不是技术转产品,所以易语言是很封闭的,后面的产品更是一代不如一代,一个小团队想要蚂蚁啃大象,没有穿透力还是不行的。但是易语言生态圈也作出了不少成功的尝试,精易论坛、世桓培训都开辟了不同的道路。

首先,易语言虽然开始在瀑布单次开发无维护式应用程序编程里火了几年,但随着时代更新逐渐被淘汰而且定位尴尬,这样的情况不能称为成功,排除那些元老级的 Fortran、Ada、ML、Forth、BCPL/CPL/C、PostScript 在外,我觉得 Basic、Delphi、Smalltalk 这种才能够算是成功过。

但是实际上因为是纯技术出身,而不是技术转产品

易语言到不如觉得是产品出身更好,我相信技术不会那么烂。就像zhong4麒麟一样。对易语言里的「易」,我觉得它的涵义就像中标麒麟是为『投标中标』里的『中标』一样,根本不是为了成为『中国标准』、成为『用户觉得容易』的语言,而是为了欺骗国家、政府和人民,自称是『方便普通人学习、推广编程技术』的语言。

所以易语言是很封闭的

这点到是真的

但是易语言生态圈也作出了不少成功的尝试,精易论坛、世桓培训都开辟了不同的道路。

我这里想吐槽一句,能设计出易语言那样辣鸡语言的作者,根本不配在编程领域提『精易』这个词,更不配在程序表达和转化领域搅合,十五年如一日没有长进我也是很服了。 易语言自它公开的那一天起,即便在工程领域的确有所建树,谈『精』、『易』,凭作者对『面向对象』和对编程语言抽象能力相关技术的理解,它没那个资格。

nobodxbodon commented 4 years ago

@duangsuse 刚写了《一种改进中文 API 可读性的方法:参数不限于在末尾》,尤其是后半部分的补充,是之前讨论时没想到的。

duangsuse commented 4 years ago

@nobodxbodon 这倒是,但不觉得容易给学习制造问题吗?

这个思路我是很赞同的(而且对中文编程很必须),但它是属于『很「中文」但不一定「编程」』的特性,如果这样的API太多了会制造问题,而语言基础库设计不够克制、过分利用这个特性会有更大问题。

一个语言特性一旦出现,对它的滥用就不会停止,并且如果保证向前兼容也就不可能停止。

如果标准库设计不够克制,以后这种语言里可能都是这样写代码——当然这里我只能举出滥用介词的例子,我不知道可不可能有更奇怪的情况出现。

变量 翻译字典 = { ',': ','  } //...
定义 把(此书:文件)里的字符替换为全角 {
  使用(把(此书)打开)时 {
    变量 新书 = 新建文件(此书的路径)模式("w+")
    对此书的字符里的每个符 {
      如果(符)在(翻译字典)里 { 在(新书)里写(翻译字典里(符)的值) }
      否则 { 在(新书)里写(符) }
    }
    新书写至系统()
  }
}

看起来好像是没什么问题,实现起来稍微有点算法基础的人也能以 trie 树这样较为简单的数据结构实现。

可是为什么不这么写呢:

量 全角:表<字、字> = 表一(','到','“等等”)
扩物 文件 为
  事 全角转化() 为
    量 新书 = 同名新建()
    对我去读全文本()里的每个符,
      新书写(全角去取值())
    新书去
量 全角=建表(','到',' “...”)
事 文件.全角化 = 内容替换,
  它去看,[c] 全角[c]。
事 文件.内容替换(:函1<文、文>) 为
  量 新=此函1(读全文本())
  文件(路径、"w+")去写(新)

另外,习语言举的例子:在(文本:section)节(文本:key)项写入(文本:strVal)

INI在"Fruits"节"TotalCost"项写入"100 CNY"

一般面向对象里可以认为是这么封装的:

INI["Fruits"]["TotalConst"] = "100CNY"
INI.sections["Fruits"].entries["TotalConst"] = "100CNY"
INI section "Fruits" entry "TotalConst" = "100CNY"

从这个角度我听人说『英文逻辑比中文严谨』是真的,因为它每个部分分得很开,xs[1]xss[1][1] 没有特别的『语法』支持。 可是这里有个问题,如果所有类似 INI[sectionName][entryName] 这样的「子结构取/置」都被写成

INI在(sectionName)节(entryName)项写入(strValue)
INI在(sectionName)节(entryName)项读出

那么 fun processSection(section: INI.Section) 该怎么写?在大型应用里这是完全有可能的吧。

如果新建一个 INI在(sectionName)节 “的引用”,那 API 是不是就更难记忆了呢? 或许可以用 completion,可依照这么灵活的『函数调用』方法,我不是特别相信在导入足够多、单个抽象足够复杂的时候它还能正常被用来写 real-world 的应用程序。要知道标准库的确是可以放很多操作和数据模型的,要是每个都可能采用 在…… 这类的调用模式…… 我到时候去看看。

语言的设计是需要深思熟虑的,仅有创意、不融合对代码一致性(同时也和学习成本有关)不能造出既自然又能够被用于实际工程实践的『中文编程语言』。

比如我对 某个语言特性 就想了半天。

引记法 绝句.额联 「以」
引记法 绝句.严格中文 「~始」

事 入口() 为
  "Hello world"以("a")始
  "Hello world"去试始为("a")

用类似 Kotlin infix 的解决方案更规范、更一致,不至于让语言显得太『灵活』,其实 infix+内联class 也是这个技巧的一种实现方法。

也许,这个特性会成为中文编程语言的一个“标志”呢。

去学校三天绝句程序设计语言的『第一人称』『第二人称』『第三人称』都被整理出来了,

同时还添加了中后缀逻辑修饰符(新语法)「不」

所以原来的 不属不存于不大 之类的都可以不必再特别规定了,isEmpty『~为空』这种也不需要再写冗余的模板 val T.isNotEmpty get() = !isEmpty 了。

nobodxbodon commented 4 years ago

@laowu2019 编写的vs code插件, auto-correct 基础上实现了中文标点符号自动替换为英文标点符号的原型。用到一个模拟键盘输入的模块

基本思路就是利用文档变化事件获取最后输入的字符,如果该字符匹配中文句号等标点符号,就先删除该符号,然后模拟键盘输入相应的英文符号。如果不模拟键盘输入的话,不会弹出自动提示、参数建议等等。这个node模块找了半天才找到 接下来可以考虑在注释中就禁用替换

有没有可能监听键盘事件,如果是中文句号就替换成英文句点,省得删除再模拟输入?

laowu2019 commented 4 years ago

找到一个新的VSCode内置方法写入字符,不需要引入外部模块。遗憾的是不能穿透python插件原生支持的jupyter notebook,期待大家帮忙解决。

liuxilu commented 2 years ago

https://github.com/program-in-chinese/overview/issues/11#issuecomment-569463904 「方法名参数位置」 相关:Multi-Part Method Names - RemObjects Elements

顺便,「用("bb")替换(列表)中的("aa")」非常恶劣,主体应该突出在前,如「替换(列表)中的("bb")为("aa")」

MaOrKsSi commented 2 years ago

大婶,这是技术,不是搞语言学,是理工科,不是文科。再说,自定义过程,有啥可纠结的呢?

在 2022-03-02 12:40:00,"liuxilu" @.***> 写道:

11 (comment) 「方法名参数位置」

相关:Multi-Part Method Names - RemObjects Elements

顺便,「用("bb")替换(列表)中的("aa")」非常恶劣,主体应该突出在前,如「替换(列表)中的("bb")为("aa")」

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you are subscribed to this thread.Message ID: @.***>

xgongya commented 2 years ago

您好,您的邮件已收到,会尽快处理回复您!

liuxilu commented 2 years ago

这听起来很熟悉。「这是理工科,用中文写什么代码?」。我只能说,每人都有自己的「理工科」。 不管是系统函数还是自定义函数,参数写在两头、主体夹在中间,都不是好主意。

nobodxbodon commented 2 years ago

@liuxilu 日语编程语言抚子中,因使用日语语法有些参数在前的例子:

締め切りは「{今年}/12/20」
今日から締め切りまでの日数差を表示   // 显示从今天到截止日期的天数差异,“今日から締め切りまでの日数差”为显示内容

参考:《关于日语编程语言“抚子”的解释》摘要(一)

MaOrKsSi commented 2 years ago

做技术,只要支持就可以了,具体别人怎么用,也不是语言的事情。你太纠结没意义的事情了。

在 2022-03-30 00:43:00,"吴烜 xuan 三声" @.***> 写道:

@liuxilu 日语编程语言抚子中,因使用日语语法有些参数在前的例子:

締め切りは「{今年}/12/20」 今日から締め切りまでの日数差を表示 // 显示从今天到截止日期的天数差异,“今日から締め切りまでの日数差”为显示内容

参考:《关于日语编程语言“抚子”的解释》摘要(一)

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

nobodxbodon commented 2 years ago

@MaOrKsSi 建议了解一下 UX。

MaOrKsSi commented 2 years ago

谢谢. 你居然把我的git找到了,我都忘记了,现在的框架已经不是这样子了。

在 2022-04-01 02:39:13,"吴烜 xuan 三声" @.***> 写道:

@MaOrKsSi 建议了解一下 UX。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

MaOrKsSi commented 2 years ago

因为无论什么表现形式,最终都要转化到:a(b,c) 的形式。

在 2022-03-30 00:43:00,"吴烜 xuan 三声" @.***> 写道:

@liuxilu 日语编程语言抚子中,因使用日语语法有些参数在前的例子:

締め切りは「{今年}/12/20」 今日から締め切りまでの日数差を表示 // 显示从今天到截止日期的天数差异,“今日から締め切りまでの日数差”为显示内容

参考:《关于日语编程语言“抚子”的解释》摘要(一)

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>