不久之前,MIT 发布 Julia 1.0 引起了极大的关注。即使我们有了 Python 这样简单易用的语言,但新语言的开发依旧源源不断。今日,Facebook 宣布开源全新语言 Skip,语法严谨、性能更好。
机器之心报道,机器之心编辑部。
Skip 是 Facebook 开发的一个实验性质的编程语言,从 2015 年到 2018 年开发了三年。
作为一个研究项目,Skip 的主要目标是探索支持准确、高效、基于记忆化(memoization)的缓存和缓存失效的语言和运行时。通过静态类型系统追踪可变性,Skip 做到了前面提到的特性,同时它也支持现代语言特征,例如 trait、泛型与子类型。
据项目介绍,Skip 项目 2018 年已经结束,Facebook 不再积极开发。至于如何继续保持该语言的稳定性,文章表示,Facebook 将会开源该语言,使编程语言研究社区在语言设计与实现、编译器和库的基础上进行研究和构建。
该语言的主要设计者是 Facebook 语言团队负责人 Julien Verlaguet,他维护了该语言、编译器与库。
Skip 概览
Skip 是一种通用编程语言,它跟踪副作用(side effect),提供反应无效的缓存、ergonomic 和安全的并行化以及高效的垃圾回收。Skip 是静态类型的,它使用 LLVM 提前编译,生成高度优化的可执行文件。
反应无效的缓存
Skip 主要的新特性是精准跟踪副作用,包括值的可变性和区分非确定性数据源与能够提供反应无效的数据源(当数据发生变化时告诉 Skip)。当 Skip 的类型系统能够证明给定函数边界没有副作用时,开发人员可以选择安全地记忆该计算,并在运行时确保当底层数据发生变化时,以前缓存的值无效。
安全的并行化
Skip 支持两种互补的并发编程,由于它跟踪副作用,这两种编程都避免了常见的线程安全问题。首先,Skip 支持使用 async/await 语法的 ergonomic 异步计算。由于 Skip 跟踪副作用,异步计算不能引用可变状态,因此可以安全地并行执行(所以独立的异步计算可以并行继续)。其次,Skip 有可用于直接并行计算的 API,同样利用其追踪副作用的特型来防止线程安全问题,如共享对可变状态的访问。
高效和可预测垃圾回收器(GC)
Skip 使用一种新型方法进行内存管理,即结合典型的垃圾回收特性和更直接的线性分配模式。由于 Skip 追踪副作用,垃圾回收器仅需要扫描从底层计算处可访问的内存。在实践中,这意味着开发者能够使用可预测 GC 写代码。
面向函数和面向对象的混合语言
Skip 的一大特点是混合了面向函数和对象的方法,整合二者形成一种具备聚合力的语言。与函数式语言类似,Skip 表达能力强,支持抽象的数据类型、模式匹配、简单的匿名函数(easy lambdas)和高阶函数等。与命令式面向对象的语言相似,Skip 支持具备继承性的类别、可变对象、循环和 early return。Skip 还整合了「systems」语言的部分理念,支持低开销抽象、通过值类的紧凑存储布局,以及确保利用静态方法调度实现代码特化(code specialization)的模式。
绝佳的开发者体验
Skip 的设计初衷是支持绝佳的开发者体验,实现迅速迭代(常见于动态语言)。编译器支持增量类型检查(使用 IDE 插件的 alpha 版本,该版本可在你输入时实现接近实时更新),提供常见的语法错误提示,帮助新手学习语言、识别方法/类别名的打字错误,甚至识别 Skip 标准库方法名的常见别名,并建议正确的名称。Skip 还主打代码格式化工具(确保一致的代码风格)和运行代码模块的工具。
初涉 Skip 语言
- 文档地址:
- 试验地址:
Hello world!
我们从经典的 Hello world 程序开始。
fun main(): void { print_raw("Hello world!") }从中可以发现很多东西。函数需要类型注释:我们指定了返回类型(void)。名为 main 的特殊函数被调用作为程序的入口点。我们没有使用关键词 return,因为 Skip 是一种基于表达式的语言:没有语句的概念。接下来我们将看到如何在序列中编写表达式。
函数
使用 fun 来声明一个函数:
fun add1(x: Int): Int { x + 1 }Skip 是一种类型化的语言,函数声明必须包括所有参数的类型以及函数返回的类型。函数的主体是一个表达式,它被评估以产生函数的返回值。
变量通过运算符 = 引入:
fun add1(x: Int): Int { y = 1; x + y }变量 y 在没有其指定类型的情况下被引入;局部变量的类型是被推断出来的,很少需要明确指定。
上面的例子还引入了;运算符,被其分开的表达式按顺序进行评估。
若要修改局部变量,需在 = 左边的变量前面加上!。
fun add1(x: Int): Int { y = 0; // declare a local with '=' !y = 1; // modify an existing local by prefixing it with ! x + y }Skip 是一种类型化语言。函数参数、返回类型和类别字段等声明都包括类型注释。编译器计算所有表达式的类型,并在遇到预料之外的类型时报错。Skip 包括常见的基元类型:Int、Float、String、Char、Bool、void。
控制流
Skip 包括常见的控制流语句,如 if、for/in、while、do 和 loop。与大部分语言不同,Skip 的控制流语句是表达式,且和其它表达式一样可以生成值。控制流表达式可用于期望使用的任何语境。
If-else
if/else 评估两个可能的表达式中的一个。
fun maybeAdd1(condition: Bool, x: Int): Int { y = (if (condition) 1 else 0); x + y }在 if 表达式的结果必须是 void 类型表达式的情况下,else 从句可能被省略。
fun maybeAdd1(condition: Bool, x: Int): Int { y = 0; if (condition) { !y = 1 }; x + y }循环
for/in 表达式使得在集合或者序列所有元素上的迭代成为可能。
fun findMax(values: Sequence<Int>): Int { max = Int.min; for (value in values) { if (value > max) { !max = value } }; max }for/in 表达式主体中的 break 表达式终结了这一迭代。
fun getAge(name: String, people: Sequence<Person>): Int { for (person in people) { if == name) { break } } else -1 // Return -1 if the person is not found. }类似地,while 和 do 循环可能包括其它子句:
fun getAgeWhile(name: String, people: Sequence<Person>): Int { iter = (); current = i(); while ()) { person = current.fromSome(); if == name) { break } !current = i(); } else -1 // Return -1 if the person is not found. }