在Common Lisp中定义多个后端的惯用方法?

Dan*_*ski 3 common-lisp clos

我想用多用户界面后端(例如文本和图形)编写代码,因此它们很容易切换.我的方法是使用CLOS:

(defgeneric draw-user-interface (argument ui)
  (:documentation "Present the user interface")
  (:method (argument (ui (eql :tui)))
    (format t "Textual user interface! (~A)" argument))
  (:method (argument (ui (eql :gui)))
    (format t "Graphical user interface! (~A)" argument)))
Run Code Online (Sandbox Code Playgroud)

这种方法乍一看似乎没问题,但它有一些缺点.为了简化调用,我定义了将在每个函数调用中使用的参数ui-type,以简化后端的切换,但是在使用高阶函数时会导致问题:

(defparameter *ui-type* :tui
  "Preferred user interface type")

(draw-user-interface 3 *ui-type*)

;;; I can't use the following due to the `ui' argument:
;(mapcar #'draw-user-interface '(1 2 3))

;;; Instead I have to write this
(mapcar #'(lambda (arg)
            (draw-user-interface arg *ui-type*))
        '(1 2 3))

;; or this
(mapcar #'draw-user-interface
        '(1 2 3)
        (make-list 3 :initial-element *ui-type*))

;; The another approach would be defining a function
(defun draw-user-interface* (argument)
  (draw-user-interface argument *ui-type*))

;; and calling mapcar
(mapcar #'draw-user-interface* '(1 2 3))
Run Code Online (Sandbox Code Playgroud)

如果采用这种方法,我们可以将通用函数命名为%draw-user-interface,将包装函数命名为draw-user-interface.

它是有效的方法还是有更简单的方法?问题是为相同的功能提供不同的后端,而不一定是用户界面.

另一个用例可能是一种情况,当我有许多相同算法的实现(针对速度,内存消耗等优化)时,我想以一种干净的方式切换它们,保留接口和参数类型.

Vat*_*ine 5

我将后端实现为单独的类,而不是传递一个关键字,因为这将允许我将各种状态挂钩到一个对象并保持它.

我可能(否则)使用你一直暗指的通用功能设计.


Rai*_*wig 5

Common Lisp Interface Manager和多个后端

支持多个后端的CLOS中的UI层的示例是CLIM,Common Lisp Interface Manager.你可以研究它的软件设计.请参阅以下链接.例如,参见类似端口协议(与显示服务的连接),介质(绘图发生的地方,对应于某种工作表的输出状态的协议类),工作(用于绘制和输入的表面,大致类似于分层窗口),移植(一个代表主机窗口的工作表),...在应用程序中打开一个端口(例如到X11/Motif之类的特定窗口系统),应用程序的其余部分应该是运行基本不变.CLIM的体系结构将其所有服务映射到特定的CLIM后端,后端为X11/Motif(或您将使用的任何端口)提供接口.

例如,该功能draw-line将绘制到工作,媒体.然后,通用函数 medium-draw-line*将实现各种版本的绘制线到一个或多个媒体子类.

总的来说,这不是很成功,因为便携式用户界面层带来了复杂性,需要大量的工作来开发和维护.在90年代中期,Lisp应用程序的市场很小(参见AI Winter),CLIM还不够好,而且实现是封闭源代码或专有代码.后来开发了一个名为McCLIM的开源/免费实现,它创建了工作软件 - 但最终开发者/用户失去了兴趣.

有点历史

在过去,Symbolics开发了一个名为"动态Windows"的用户界面系统.它于1986年发布.它运行在Symbolics操作系统中,可以绘制其原生OS /硬件组合和X11.从1988年左右开始,开发了基于便携式CLOS的版本.第一个可用的版本(特别是1991年的1.0版本)可以在几个平台上使用:Genera,X11,Mac和Windows.后来开发了一个新版本(版本2.0),它再次在各种系统上运行,但包含一个复杂的面向对象层,它提供了一个更明确的后端层,称为Silica.这个后端层不仅支持便携式绘图等内容,还支持抽象窗口系统的部分内容.更加雄心勃勃的部分,例如支持外观和感觉的适应(滑块,窗口样式,滚动条,菜单,对话框元素......)都没有完全解决,但至少可以作为第一代版本使用.

指针

CLIM导览,Common Lisp接口管理器(PDF)

二氧化硅:二氧化硅的实施反思(PDF)

规范(包括Silica):Common Lisp Interface Manager 2.0规范