本文记载了我个人对编程语言的一些想法。我认为,这些都是技术上可行的,之所以没有出现,只不过是“没那么多人想要”而已。也许这些功能都已经存在了,毕竟我只知道我学过的语言。
契约就是代码中的谓词,通常以函数的形式出现,并像其他断言语句一样处理。从银行账户中取款的示例如下:
method withdraw(amnt: int)
requires amnt <= self.balance
ensures self.balance >= 0
{
self.balance -= amnt;
}
Eiffel语言曾经是标准的契约语言,但从上世纪九十年代中,就被人们遗弃了。现在唯一的主流契约语言是Clojure。大多数语言都有契约库,也就是说,这些语言并不能很好地使用契约。例如下面这个 is_sorted(l) 谓词:
forall i, j in 0..len(l):
i < j => l[i] <= l[j]
大多数语言都有 all 和 any 函数,但并不允许对多个元素进行量化,而且基本上没有任何语言支持隐含操作符(因为隐含操作符在编程中几乎没有用处)。我希望看到一种语言,能够将契约很好地集成到语法中。至少,前置条件、后置条件和内联断言都应该有专用的语法。还需要能够标记和重用谓词的能力,以及处理“正交”谓词(只有当A'的前置为真时,才检查A的后置),等等。
还有工具的集成!Eiffel的一项很好的功能就是利用契约来推断测试。如果有契约,就可以通过fuzzer迅速生成集成测试。Clojure的Spec的功能与此类似。
继承和接口是类之间的关系。那么函数之间有什么关系?例如下面这两个函数:
def window1(l, n):
if len(l) < n:
return []
out = []
for intervals in range(len(l) - (n - 1)):
window = l[intervals:(intervals+n)]
out.append(prod(window))
return out
def window2(l, n):
if len(l) < n:
return []
out = []
val = prod(l[0:n])
for i in range(n, len(l)):
out.append(val)
val *= (l[i] / l[i-n])
out.append(val)
return out
这两个函数用于计算列表 l 的滚动乘积,因此 window1([1, 2, 3, 4, 5], 2) == [2, 6, 12, 20]。window2是window1的优化版,对于每个输入,其输出应该与window1相同。这一点应该能在语言中体现出来,工具也应该能检查这两个函数的输出结果相同,并运行性能测试,看看是否优化版确实更快。
我还可以想出其他关系。A'是类A的可测量版本。g 是一个反函数,使得 f(g(x)) == x。P'是P的正交子类型,但不是里氏子类型。UML有类似于“traces”、“refines”、“generalizes”等关系, 因此编程语言中也可以存在类似的关系。重点是,我希望能在语言层面表达这些关系,从而让编程语言能利用这些关系。
这些关系也可以用于契约,比如用于保留/转换/扩展契约的关系。很常见的一种就是“继承的方法有更不严格的前置条件和更严格的后置条件”。还有什么其他关系?
Lisp:一切都是列表。
Bash:一切都是字符串。
Smalltalk:一切都是对象。
APL:一切都是数组。
图是一种很常见的数据结构,但并没有哪种语言是“一切都是图”的语言。实际上,几乎没有哪种语言的标准库会支持图!这可能是因为图是一种非常复杂的数据结构。你知道链表有多烦人吗?图比链表麻烦1000倍。
尽管如此,我还是希望看到有人尝试一下!比如,键值映射用有向图模拟。
我对于J爱恨交加。语言本身有很多让我抓狂的地方,但我依然要用它,因为这是唯一接近于桌面计算器的语言。当需要在项目中进行快速计算时,我关心两点。第一,击键次数。下面是在Python中计算阶乘的乘积的方法:
import math
prod([math.factorial(x) for x in l])
太麻烦了!在J语言中非常简单,只需要 * / ! l,击键次数少一个数量级。在需要试验各种公式时,击键次数就很重要了。但是J语言中“一切都是数组”,这就限制了它作为计算器的潜力。它没办法很好滴处理字符串、JSON、集合或哈希表,日期操作非常繁琐,对于组合问题也束手无策,等待。我希望有一种语言能满足一切需求。最好还能给操作符加上命名空间。
我希望计算器拥有的另一个特性就是内置的响应式编程,大概就是一种文本编程语言和Excel的结合体。我希望能实现下面的功能:
input = 1
out1: input + 1
#out1 is now 2
input = 4
#out1 is now 5
out2: out1.replace(+, -)
#out2 is now 3
# let's pull an APL
input = 4 2
#out1 is 5 3
#out2 is 3 1
当然,这会非常难学,但我已经续学过了许多奇怪但强大的语言。交互式计算非常常用,我学了很多知识来完成这项工作。
……或许我应该安心使用Excel。
(有人会说,Smalltalk就是百分百的动态类型语言)
静态类型非常好!静态类型语言有很多很酷的东西,但动态类型语言并非如此。许多研究都在朝着给动态类型语言添加类型的方向努力。我认为,动态类型本身也有许多有趣的方向可以尝试。例如,可以在运行时生成新的类型!将此功能与契约结合,就可以给变量添加约束,例如:
type Interval(x, y) <: Int {
x <= self <= y;
}
var i: Interval(1, 10) = 3
i += 7 #ok
i += 1 #error!
很酷吧?我还不知道这个功能是否有用(也许只是类的语法糖),但它依然很有意思。我想看看人们会怎么用它。
我还希望能够在运行时更改函数定义。在我看来,一个程序把其他程序作为输入读入再运行,然后我还要去实验该程序在特定状况下的行为,这简直就是噩梦。我希望能实现元编程。
我好怀念VB6。
原文地址:https://buttondown.email/hillelwayne/archive/six-programming-languages-id-like-to-see/
— 推荐阅读 —