Skip to content

about dot syntax

· xieyuheng

长期以来,我一直认为很难为 lisp 设计 OOP 中的 dot 语法。

今天在尝试设计类似 C 的 system-lisp 中的 struct 功能时, 我发现可以完全舍弃 dot 语法,而改用生成 identifiers:

scheme
(define-struct (node-t A)
  (prev (optional (node-t A)))
  (next (optional (node-t A)))
  (value A))

(define-struct (list-t A)
  (first (optional (node-t A)))
  (last (optional (node-t A)))
  (cursor (optional (node-t A)))
  (length int-t)
  (free-fn (optional (-> A void-t)))
  (equal-fn (optional (-> A A bool-t)))
  (copy-fn (optional (-> A A))))

(claim new-list (polymorphic (A) (-> (list-t A))))

(define (new-list)
  (new list-t :length 0))

(claim list-free (polymorphic (A) (-> (list-t A) void-t)))

(define (list-destroy self)
  (list-purge self)
  (free self))

(claim list-purge (polymorphic (A) (-> (list-t A) void-t)))

(define (list-purge self)
  (= node (list-first self))
  (while (not (null? node))
    (= next (node-next node))
    (unless (null? (list-free-fn self))
      ((list-free-fn self) (node-value node)))
    (free node)
    (= node next))
  (list-put-first! null self)
  (list-put-last! null self)
  (list-put-cursor! null self)
  (list-put-length! 0 self))

类似的,之前设计的 cicada-lisp 中的 OOP 语法, 也可以从使用 : 作为 dot 语法:

scheme
(define-class functor-t ()
  (claim dom category-t)
  (claim cod category-t)
  (claim map (-> dom:object-t cod:object-t))
  (claim fmap (implicit ((x dom:object-t)
                         (y dom:object-t))
                (forall ((f (dom:morphism-t x y)))
                  (cod:morphism-t (map x) (map y)))))
  (claim fmap-preserve-compose
    (implicit ((x dom:object-t)
               (y dom:object-t)
               (z dom:object-t))
      (forall ((f (dom:morphism-t x y))
               (g (dom:morphism-t y z)))
        (equal-t (cod:morphism-t (map x) (map z))
          (fmap (dom:compose f g))
          (cod:compose (fmap f) (fmap g))))))
  (claim fmap-preserve-id
    (forall ((x dom:object-t))
      (equal-t (cod:morphism-t (map x) (map x))
        (fmap (dom:id x))
        (cod:id (map x))))))

改为生成 identifiers:

scheme
(define-class functor-t ()
  (dom category-t)
  (cod category-t)
  (map (-> (category-object-t dom) (category-object-t cod)))
  (fmap (implicit ((x (category-object-t dom))
                   (y (category-object-t dom)))
          (forall ((f (category-morphism-t dom x y)))
            (category-morphism-t cod (map x) (map y)))))
  (fmap-preserve-compose
   (implicit ((x (category-object-t dom))
              (y (category-object-t dom))
              (z (category-object-t dom)))
     (forall ((f (category-morphism-t dom x y))
              (g (category-morphism-t dom y z)))
       (equal-t (category-morphism-t cod (map x) (map z))
         (fmap (category-compose dom f g))
         (category-compose cod (fmap f) (fmap g))))))
  (fmap-preserve-id
   (forall ((x (category-object-t dom)))
     (equal-t (category-morphism-t cod (map x) (map x))
       (fmap (category-id dom x))
       (category-id cod (map x))))))

相比 dot 语法,这样更简单,看起来也更和谐。

反思 ​

我差点又因为 lisp 不好设计 dot 语法,而放弃了 system-lisp。

这次没放弃是因为:

  • 想起了 "OOP is absurd" 这条 belief。 而这条 belief 的推论是:不应该为了 dot 语法而全盘接受 OOP。

  • 已经实现的 x-lisp 中没有 dot 语法也用的好好的。

注意,如果之后需要大量使用到 structural record, 可能还是要为 x-lisp 的 record 语法加上 get 和 put! 语法关键词, 以代替 record-get 和 record-put!。