Lisp的生产性

竟然没人提到 grammerly 耶

学姐肯定是没看到

哈哈哈哈哈哈哈

不仅仅是能写,最主要是其抽象能力,省去了实现细节。小的例子是 when-let ,大的例子是 use-package,在一个大型软件里面,这层抽象尤为必要。

函数也能起到抽象的作用,与 macro 什么区分呢?

macro 是编译时期执行的函数

说白了,macro 也是函数,只是执行阶段不一样。

总结的不错,我这里补充下原因。因为上面说了,macro 本质也是函数。之所以 function 比 macro 更容易利用,是因为现有函数都是为操作具体业务数据而写的,而 macro 这类的函数,是以 s-exp 为主要操作目标。

这句话感觉也能再延伸下。Macro 不仅仅是让语言更简洁,而是创造一个“新”语言。举一个 cascalog 的例子:

(?- (stdout)
    (<- [?word ?count]
        (sentence :> ?line)
        (tokenise :< ?line :> ?word)
        (c/count :> ?count)))

上面代码片段是大数据领域一个经典示例 word count(类似于 hello world),cascalog 虽然是用 Clojure 写的,但是用法完全是个“新”语言,熟悉了这个“新”语言可以很方便的进行 map reduce 程序编写。

2 个赞

这样似乎和 web 前端造的各种工具有点类似, 比如 purescript, typescript 和 babel, 思路上都是把不同的语言转换成 javascript. Racket 这边的话, 看起来似乎是想用 macro 代替那些编译器实现这些转换功能.

感觉确实会有些问题, 一个是 Racket 语法本身的灵活性能不能很好兼容各种语法, s-expression 虽然已经比较灵活, 但是很难涵盖到各种方面. 另一个是如果想要实现比较复杂的语义, 虽然理论上可行, macro 本身的复杂度和性能就挺难控制的. 综合下来, 除了小规模并且比较简单的 DSL, 很可能不如专门的编译工具好用.

在最后这个例子里面,我觉得只有 <- 是个 Macro,目的是可以方便的直接用 symbol ,这个东西同样的可以使用函数来实现,把 ?word ?count 换成 :word :count。甚至可以用数据结果来表达,只是数据结构的约束消失了,这里也不太需要数据结构的可操作性。

我觉得在 cascalog 这,设计确定下来之后,对于做 map reduce 这件事的方式就很确定了,这一整套的设计就体现了解决这个问题的主观的思路。是不是高效更取决于设计,而不是用宏或其它什么方式来表达。

对,我是这个意思

更一步抽象的来讲,*script和racket的方向都是通过完善工具链把写compiler变成写interpreter的问题

同意,其实我看到的ML系在写DSL上面做的学术研究要比Racket多哈哈 (比如tagless final等等)

Racket虽然是language oriented,我也确实是使用过多个语言(racket, typed/racket, video, scribble, slideshow, redex等等) 但他们的内部实现是不统一的,意思是没有一个写DSL的通用标准,对于我这一个non Racket expert来说,还是有点小劝退的

当然最重要的一点是,racket并不能很好的实现有类型系统的DSL,尽管这几年出了个turnstile

为啥是意识形态的原因?国内的项目不让用Clojure开发吗?

说实话 JVM 我还不如觉得 dotNET Core 这样一个装个库就能用FFI调用有吸引力。

让我想起王垠以前的一篇文章。《DSL的误区》。 https://henix.github.io/feeds/yinwang/2017-05-25-dsl.html

我最近开发的项目就是用 JS(WebComponent) + Postgres + Common Lisp
Common Lisp 用了我自己这半年慢慢积攒下来的工具项目(上次我在这里提过 就是Postgres写的函数, 在JS立刻很方便就能调用 配上Web Socket)

可能ERP系统就是这样, 大部分就是依赖数据库吧
我最近这整个系统用到的Lisp 代码可能一两天就写完了, 其他的就用是JavaScript 和 SQL

刚好我今早上(睡觉前)就写了一个全局同步通知功能的功能 机构所有人都会实时同步数据消息(就跟玩网络游戏一样) 还有系统弹出提醒

1 个赞

选 VM 的话选生态不选特性嘛

总的说的很好,提几点补充:

  • 从功能目标上说,macro 还能实现诸如C编译器的conditional compile所能达到的适配和性能优化的特性。

  • macro减少样本代码这点上来说,的确是能够做到object oriented类的语言所提倡的template method设计模式, 其实procedure也是能优雅的做到的,差别只在于macro expansioninlineprocedure body中的,少了一次procedure call的开销,在这点的表达力上这两者是没有差别的。

  • 与其说macro本质上是procedure, 那只不过从使用上看是相似的,倒不如说它们都是lambda expression;理由是macroevaluation order完全不同于procedure,这点上macro倒是很好的印证了data as code。另外macro还有一个expansion的过程,这个有点类似C++template instantiation的过程, 由于Lisp环境中的compile-time, run-time是个交织的过程,所以要比C++template复杂和高级。

总的来说我也算是 Common Lisp 实战的半个老手了, 我觉得

  • macro 就像我们语言的 副词/adv, 用来修饰动词, 这样的话一个副词可以修饰很多常用的动词, 就像从小我们就经常学的 成语, 比喻 这些, 用一个短短的词句可以概括很多场景, 这样我们就不用每个稍微有点不一样的场景就要记住不同的词去描述了, 听众也是要理解和知道的词语也更多成本也就更多了

  • 以前我也在这里的某个帖子提到过, macro 就像是我们生活用语中的副词, 修饰生活用语的"动词", 也就是function, 而我们的语境,就像 《PCL》第6章里讲了的 “Lexical Variables and Closures/ Dynamic, a.k.a. Special, Variables

  • 我们有时也会动词和副词同一个词, 英语单词副词和形容词(也是function吧)也常见合在同一个词

  • BTW, 近期又有新的理解(我是要发挥活到老学到老到极致啊!), 函数说白了就是用更精简的词句来概括更长的句子(不就如成语吗??), 本质上 macro也是函数
    (记得刚上大一时看到那些代码有点发愣, 怎么那也叫做函数!? 函数不是跟中学时那样的 xyz这些混搭起来的吗?
    其实xyz这些数学函数本质上也是为了对某些数据有关的问题更好抽象更简单)

要不然同学们尝试思考下, 假如我们的话语没有副词 (动词, 形容词这些都会有)会怎么办?

说白了, 就是抽象好能让你用乘除法取代加减法, 甚至用 指数/对数来取代乘除法
[反过来说, 不懂得抽象的, 就经常很词穷, 但是词穷的人也是可以用较长的篇幅来描述自己的意思(弥补macro?), 虽然不一定很精准]

9 个赞

AutoCAD

Oh, TLTR;

用喻指的方式来描述事物通常是不严肃的,除非是文学作品。

macro 就像我们语言的 副词/adv , 用来修饰动词

这样说就不妥当,如果问:“副词能像动词一样使用吗?如果是一样的那如何区分究竟是动词还是副词呢” 那么你的这个说法就站不住脚了,因为macro是可以像procedure一样使用。当然你试图去弥补这个漏洞,在以下这点能看出来

  • 我们有时也会动词和副词同一个词, 英语单词副词和形容词(也是 function 吧)也常见合在同一个词

虽然某些(当然不是全部)英文词在拼写上副词和动词是一致,但不表示它们是同一的,至少在上下文中的使用上能区分,对吧。所以结论是你的这个说法不妥当。既然你懂Common Lisp, CLLisp2的对吧,我就举个CL的例子:

(defvar foo 2)
(setf (symbol-function 'foo) (lambda (x) (* 100 x)))

(+ 1 foo) ;; variable
(funcall 'foo 3) ;; procedure

foo symbol即作为variable, 也作为procedure, 但在使用上我们来区分它们一点难度都没有。

就是 抽象 好能让你用乘除法取代加减法, 甚至用 指数/对数 来取代 乘除法

这个说法同样也不妥当,在算术上用乘法来计算和用加法来计算得出的结果一致,这并不能说明乘法在抽象级别上就比加法高,在数学上乘法和加法都同样重要。扯个题外话,早期的CPU是没有乘法器的,都是加法器。

对于抽象问题,哲学、数学、工程学上都有不同的蕴含。对于我来说,我不具备对高深的问题真正据有那种真知灼见的能力,这个就闭而不谈了。曾经在数学上被如此教育:“这个推导要多考虑下,要更抽象点”, 这里的抽象我知道是要more general些;"明天的太阳"和"太阳"比,我也能猜的到“太阳”更抽象,因为少了"明天的"限定当然更more general

成语就像是我们都熟悉的(成语我们大部分都是小学学的吧)通用开源代码库,即拿即用,可用完即走

我们用成语的时候不需要解释它的意思,大家都心灵神怡,很清楚它的意思(就像你用的开源流行代码库的函数,大家都已经很熟悉了,你不需要再注释那些函数),而且比自己再用长长的日常用语解释更准确不容易被误解,就像高性能的代码库已得到了“缓存”,胜过你重新自己去实现,不仅仅是性能,还有出bug的概率更低

1 个赞

AutoLISP

1 个赞

突然想到,前面提到的抽象有点像成语,不针对具体哪几件事物
而成语又接近Pointer 指针,32 or 64bit 指向一个较大的数据,成语也一样