时隔多年我又再一次体验了一把跟大神聊天的感觉
跟大神聊天是很开心的。这不是因为我激动,而是因为大神说出来的每一个字都是有价值的,一针见血,毫无废话。至于为什么说又,当然是这种事情以前发生过。
第一次是在高中认识了龚敏敏。那个时候我刚做完那个傻逼的2D ARPG不久,龚敏敏已经是M$RA的实习生了,图形学上的造诣肯定要比我高许多,其中的差距构成了大神跟菜鸟的关系。当然现在我尽管中心已经放在了程序设计语言(programming language,以下简称PL)上,但是还知道一些图形学的内容,跟龚敏敏的差距自然也已经缩小到了不构成大神和菜鸟的关系的程度了。尽管他还是比我多知道很多东西。
第二次是在大学的时候认识了g9yuayon。g9菊苣是做形式化和证明的,自然也知道很多PL的事情。那应该是我大二的时候,在CSDN上偶然发现了g9菊苣的博客,觉得文章写的很好,就顺便把博客上面的email“密码”给破了之后发email给他。后来g9菊苣告诉了我很多诸如在哪里可以获得知识的事情,于是我也就做了PL。尽管现在已经很少跟g9菊苣联系了,不过我感觉目前我跟g9的差距应该还属于大神跟菜鸟的关系,因为他很久以前写的博客我都还不能完全搞明白。
第三次就是今天的事情了。大家都知道最近我在写一个《如何设计一门语言》的系列文章。这个系列文章肯定是会继续写下去的,因为我的语言都还没做出来。所以可以很明显地看出来,我现在也在做一个语言。这跟王垠的那个one当然是不一样的,因为我从一开始就没打算代替所有东西,而且目标也很明确,就是把它做成跟C++/C#一样,菜鸟可以很容易上手写出清晰易懂的代码,大神也可以在里面挖掘出很多奇技淫巧。于是我不可避免的就遇到了CPS的问题。
大家都知道C#有yield和await两个关键字,F#也有computation expression。于是我就在想,如果yield和await不是关键字,而是一个函数,会发生什么事情。展开来讲,就是如果要让程序员自己实现一个为特定目的服务的CPS变换,那我的语法要怎么做。对于没有怎么设计过程序语言的人来说,“设计一个语法”这种事情其实是很容易被误解的。语法并不是说要在这里放一个括号,在那里放一个关键字,在别的地方还能省略一个什么东西(瞧瞧go抄了javascript那个屎一样的分号省略策略)。这些都属于品味的问题。品味是不需要设计的,那是靠感觉的,是一种艺术。只要你拿出来觉得漂亮,那就是好的。真正需要思考的东西是什么,那自然是围绕早上面的类型系统了。
我用通俗易懂的方法来解释一下,什么是类型系统,或者说在我们这些做PL的人看来,眼中的程序大概是什么样子的。我们拿一个C#的异步程序来说,其实也就是上一篇文章讲的那个例子了。
async void button4_Click(object sender, EventArgs e) { try { string a=await Http.DownloadAsync(url1); string b=await Http.DownloadAsync(url2); textBox1.Text=a+b; } catch(Exception ex) { textBox1.Text=ex.Message; } }
大家都很熟悉吧。如果这个这么简单的程序还看不懂的话,那肯定是没有认真阅读我的《如何》系列。好了,现在开始来讲,做PL的人到底是如何看待这个程序的呢:
async void button4_Click(Object, EventArgs) { try { String=await (String -> Task<String>) (String); String=await (String -> Task<String>) (String); (TextBox -> String -> Void#TextBox.Text) (TextBox, String + String); } catch(Exception) { (TextBox -> String -> Void#TextBox.Text) (TextBox, (Exception -> String#Exception.Message) (Exception)); } }
嗯,差不多就是这个样子。这个函数究竟是下载一个盗版小说,还是下载一个带节操的日本电影,究竟是同步下载,还是异步下载,是下载到一个文件夹,还是下载到skydrive——关我屁事!我只看这里关于类型的部分。
所以,如果await是一个函数的话,那他应该是什么类型?如果yield也是一个函数,那他应该是什么类型?如果这门语言让程序员来创建属于自己的await和yield甚至是他自己的想要的计算,那我应该如何做一个框架让他往里面套,或者他写出来的这个函数究竟要在什么上下文里面满足什么样的一个类型的关系呢?我最近就一直在想这个问题。
一开始我就把目光投向了F#的computation expression,因为F#的这个东西就具有我想要的一切功能。后来我想把这个功能搬进来的时候,发现怎样都套不上。当然我很快就发现了,这其实是因为F#归根结底还是一个函数是语言,他是不能在一个for循环里面写break、continue或者return的。F#的一个for循环,永远是一个完美的for循环。但是我的语言是可以的,于是这样在类型上就不完美了——不过这是小事,牺牲一点点完美换来易用性是值得的。当然,牺牲很多完美来满足易用性,我觉得是不值得的。
既然for循环里面可以带break/continue/return,那么“我的computation expression”的For函数,就不能是类似于IEnumerable<T>->(T->M<U>)->M<U>这种纯粹的东西了。那我应该怎么做呢?
写到这里,我觉得在微软工作就是好啊。关于编程语言领域的很多改进其实都是从微软这里做出来的。通俗的部分,看看完美的C#,看看ASP.NET MVC的razor模板在Visual Studio里面的智能提示的功能——这可是一个可以混合HTML+CSS+Javascript+C#的代码,写的时候丝般顺滑,行云流水,俨然这四门语言就是一门语言一样。在学术上,微软的各个研究院也贡献了相当多的东西——不过我觉得你们对这些应该是不感兴趣的,尽管你们在linux上面也用了很多微软的成果。
那这能说明什么问题呢?这就意味着,我可以随时access到微软做编程语言的大神们,抓他们来问问题。不过他们是很忙的,经常不在线(我们也有一个类似QQ这样子的东西)。不过今天我随手打开了一下,展开了我积累的几个大神的组,发现F#他爹竟然是绿的,于是我随手就发了一句hi,看看人家在不在。人家回了我,于是我就开始问这个问题了。
什么,你不知道F#他爹是谁?他当然是Don Syme了。写函数式语言不认识Don Syme,就犹如读物理不认识牛顿,读数学不认识柯西,写C++不知道Bjarne Stroustrup,用操作系统不知道Dave Cutler一样,要跪着爬回自己学校里重新读书。(其实这只是一个艺术手法啦,不用在意,我也不知道他们到底不认识谁才要跪,啊哈哈哈哈)
Don Syme是微软的Principle Researcher,翻译过来大概就是“顶级科学家”的意思吧,很少有更牛逼的东西了。
于是故事到这里就结束了,因为Don Syme大神他很快就回复我说,如果for循环支持break/continue/return,那我就不应该从F#的computation expression里面获取灵感。至于我的问题要怎么办,这还是个open question。于是我们愉快的聊天就用下面的一句话结束了:
Don Syme: Research