大家都用scheme做些什么

很长一段时间没碰过scheme了,最近我把官网上列出的所有scheme实现都玩了一下(然而我并不使用scheme工作)。我感觉这个lisp方言像是科研人员的玩具,scheme的功夫跟这门语言自身半毛钱关系都没有。语言的设计到处都弥漫着简洁,可是很多无聊的工作却常常要自己完成。所以我认为它并不适合行动上的懒人。我知道有大量的实验性编译器使用scheme作为目标语言,但是其它方面几乎看不到以standard scheme为主力的项目。

而且,scheme的native code compiler似乎也并没有非常好的实现。scheme compiler的性能这方面,有人了解吗?我在github上发现有一个scheme-to-llvm的项目,但是这个项目并没有推进下去。

chez scheme or gambit scheme.

等 R7RS-Large 吧,这么多年了 Scheme 的生态依旧是一盘散沙,没有玩的动力了。

Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. — Revised 7 Report on the Algorithmic Language Scheme, Introduction.

工程上用的确实少,但 scheme 一直是探索编程语言能力极限的重要工具。

我用得不多,主要是把特定格式输入利用 macro 编译成 SMTLIB 格式用 z3 求解,我平常不用 Python,通过用 C++ 调用 z3 又不如用 Scheme 处理输入方便

How to Break Hatsune Miku Logic Paint

2 个赞

Chez 最好,其次 Gambit,其他就无所谓性能了

用 LLVM 当 JIT 的项目,尤其规模不大的,一般性能不会比 Racket 好多少,说白了就是没有功力自己搞生成汇编,用 LLVM 偷懒的表现。

1 个赞

我用GNU guile做单元测试胶水语言。软件是C++的,各种函数封装成scheme function。然后用guile实现测试向量生成,测试流程等等。

2 个赞

R7RS-Large还是算了吧,十几年的时间都够做好几个新语言了,也没有啥杀手特性,而且就连R7RS-Small都没人做Chez这样的“正统”并且full-featured实现(s7不全,Chibi难用,Gauche、Guile、Chicken全都有自己的历史包袱,积累了一大堆非正交特性),很难相信Large出来之后会有什么改观。我觉得指望标准进程还不如指望谁谁谁

  1. 把SRFI给全部实现了(除了重复的),这样至少开箱即用,并且有一些甜品特性。

  2. 做完LIPS或者类似的东西,白嫖JS或者别的什么语言的生态,反正大家都干了。

  3. 多弄几个别的语言的库或者框架的binding,并且积极维护。

也就是在脚本语言这条路线上一路走到黑,至于生态和Lisp的倔强,那还是算了吧

1 个赞

不赞同,与其声明SRFI的所有权,还不如全盘推倒SRFI搞一套更好的生态规划。

要是用llvm做后端就好了,就不用像chez那样每个后端的codegen都自己实现一遍了。

1 个赞

guile在这方面的确得天独厚,本来就是为了服务gnu make和gdb。我比较好奇使用guile是否有一些绝对意义上的优势?

比如说,如果我使用lua或是ecl,是不是也很容易做到相同的事情?

但是llvm ir也可以转成native code,这样的话效率会高很多吧。

Racket (both before on Chez and on Chez) 生成的也是 native code,效率就没好到哪去

LLVM 只能优化到生成汇编前的最后一歩,对函数式语言(以及 OOP)本身高层次的优化没做好,用上 LLVM 也不会有高性能。

快十年前的一篇讽刺 Scheme R7RS 设计的文章

Arcane Sentiment: If Scheme were like Scheme

大意是 Scheme 除了 number 类型以外,其它所有数据类型的 library 都设计得很糟,如果把 number 设计成和其它 library 一个风格的话,很显然就会发现没有重载,命名又臭又长,没有序列化,和其它 library 过于割裂,除了基本操作以外提供不了其它实用常用的操作

1 个赞

Scheme的标准库过于离谱,以至于我觉得它其实是在构筑某种“核心”来为“大的”铺路。然而除了在Racket的第三方库中以鸡零狗碎的形式出现之外,我从没见到这种“大的”付诸实施(况且单纯靠R7RS的 define-record-type syntax-rules 也整不出啥花活)

顺便,这篇文章里取消数字字面量的设想我还挺喜欢的。数字表示法千奇百怪,在不同语言和实现里不尽相同,其中一些还真不是人人都需要的,跟各种前缀语法/宏一样降低了s表达式的可移植性,与其作为字面量不如作为构造器宏的操作数

https://akkuscm.org/ 这个堪用吗?

不堪用,但不是包管理器自身的问题

  1. 包少,而且有很多重复的,比如SXML、早期SRFI、match都有很多版本
  2. 标注为R6、R7的并不一定真的可移植,比如 (chibi match) 只import了标准库,但实际上依赖非标准的is-a?(其实想想也知道,光凭标准库不可能根据记录类型描述符判别实例)
  3. 标准没有规定源代码在文件系统中的存取方式,实现各种放飞自我,而Akku尽管尽了最大努力,却仍然不能兼顾。比如SRFI库会被自动软链接和shim为带各种前缀和扩展名的版本,但是Guile还是识别不了
  4. 纯Scheme包本来就意义不大,这种语言归根结底还是要靠FFI binding,但是FFI binding并不可移植,况且Akku也没收录多少

总之从实用性上,Akku还比不上 raco pkg。但是后者工作方式太原始、简陋了,而且Racket自身的静态性也使得它不是很通用,因此硬要开发标准Scheme程序,还是只能选择Akku。

2 个赞

Lisp 这样的动态语言在 LLVM 上的表现看 Common Lisp 的 Clasp 就知道了,目前的性能和 native-comp 的 Emacs Lisp 差不多。

看一看我这个刚刚发起的Scheme解释器的标准库?

我在模仿Python的标准库,提供Scheme的实用性。

感觉 Scheme 对我的意义就是教学语言,有很多语用都是第一次在 Scheme 上见到的(懒惰求值、高阶函数、宏、尾递归优化……)。 目前大概能算用到 Scheme 的地方是一种电路描述语言叫做 EDIF?其实也不算 Scheme,就是类似于 XML 的序列化,只是用 S-表达式来做的,用来记录电路数据。

2 个赞

没有重载那点,不是因为 lisp 文化里很多类型实际上没有自己的 tag 只通过 predicatite 判断其是否为该类型并作出响应嘛。我想所谓没有重载大概是说标准库没有自带一些函数可以在某些固定类型上分派…?比如既能用于 list 又能用于 vector 的 fold、filter、map 这样子。

序列化如果指的是二进制序列化,r7rs large 说是会有一个。

命名长那点说实话 Common Lisp 中就初见端倪了。其实 Java 命名也很长虽然广受诟病但看来大家不是不能接受 命名长在我看来确实是个问题。

除了基本操作以外没有提供其它实用的操作——这个在我看来确实有些问题,教学目的另说,C++ 在这个问题上都有改观。