将"EngMath"(数学本体)从lisp转换为OWL



1994年,早在OWL规范之前,Thomas R.Gruber和Gregory R.Olsen就出版了《工程数学本体论》。由于缺乏任何特定于本体的语言,它是在lisp中实现的。lisp代码仍然可用(参见示例),但不能被现代OWL本体使用(也就是导入)。

使这个本体可用于当今(基于OWL的)工具链的最简单方法是什么?

有两种可能的方法来解决这个问题:你想采用哪种方法在一定程度上取决于编写这个本体的系统是否仍然可以访问。这些方法在拯救其他用Lisp编写的旧包时很常见,所以我认为它们值得描述。

这个答案并没有给出如何做到这一点的详细说明,因为这个过程一定是迭代和实验的。

软件是如何开发的(在Lisp中)

有一件事经常让人困惑,那就是这个系统根本没有在Lisp中真正实现。

用计算机解决问题的一个很好的方法是首先实现一种语言,在这种语言中可以很容易地谈论问题领域。这是一种非常常见的方法:大量的大型系统涉及一种或多种专用语言。例如,驱动现代系统的所有小型配置文件格式实际上都是小型专用语言。任何曾经在大型软件系统上工作过的人都会遇到大量这样的东西。

它们中的大多数都会很糟糕,因为它们是由不知道自己在做什么的人写的:他们不明白自己在设计一种语言,而是认为自己在做其他事情,通常包括用基于模式的其他字符串替换字符串。

Lisp是少数几个对此持开放态度的语系之一:在Lisp中解决问题的方法非常明确,就是编写一种可以更好地表示问题的语言。该语言(通常)表面上看起来有点像Lisp:它将使用带括号的前缀表示法等等,但它也将包括底层Lisp中根本不存在的结构。(事实上,现代Lisp本身就是这样的语言:它们是以更简单的版本实现的语言。)

因此,EngMath系统是一个用在Lisp之上实现的语言编写的程序:它根本不是用Lisp编写的。这种语言要么是KIF,要么是Ontolingua:我不明白这两者之间的关系。

第一步:拥有一个Common Lisp环境

所有这一切的第一步是拥有一个高质量的Common Lisp环境,并对其使用有所熟悉。我不会在这里推荐一个,因为我在这方面还很不了解,但有几个是免费的。

如果底层本体语言仍然可用

所以,若底层语言的实现仍然有效,那么拯救系统的第一种方法就是使用它。我不知道是不是这样:斯坦福大学KSL网站上的许多链接现在似乎都指向任何地方,所以它可能仍然存在,也可能不存在。正如我上面所说,我认为底层语言要么是KIF,要么是Ontolingua(可能是Ontollingua是KIF的实现?不确定)。

方法如下。

  1. 获取要在Lisp中构建的底层本体语言。这可能很难,也可能不难:Common Lisp一直很稳定,但一些旧程序在该语言的临时版本中写得非常草率,这取决于特定的实现特性
  2. 用这个重构的语言加载你的本体
  3. 用重建的语言测试它
  4. 充分了解与本体相对应的对象的实现,以便进行下一步操作。这将涉及阅读和实验底层本体语言的源代码
  5. 编写一个程序(以本地Lisp和底层本体语言的某种组合),该程序可以遍历与本体相对应的对象,并以您想要的某种格式打印它们(可能是OWL?)
  6. 利润

这将是一项艰巨的工作。请注意,如果您只想使用本体,您可以从上面的步骤(3)分支:一旦系统运行,您就可以使用本体。

如果底层本体语言仍然不可用

如果底层语言变得有效或真的不可用,您可以使用这种方法。它也可能是一种更好的方法,即使仍然可用,如果你想做的只是转换。

  1. 了解底层语言中数据的表面表示是什么。如果语言是KIF,那么至少有一些幸存的论文可能会对你有所帮助
  2. 说服Lisp阅读本体源。这可能并不像看上去那么难:看起来你发布链接到的本体部分并没有使用任何特别奇怪的读取级别语法。有关此方面的更多信息,请参见下文
  3. 编写一个伪填充程序,允许Lisp构造与本体相对应的伪对象。这也应该相当简单:见下文
  4. 一旦有了这些伪造的对象,就可以对它们进行处理,以发出合适的OWL输出。这将涉及到对旧本体语言的足够理解,以便能够将用它编写的东西转换为OWL
  5. 利润

这种方法仍然很痛苦,但可能没有第一种痛苦:如果原始系统丢失,这也是你所能做的。我用古老(非常古老)的代数系统编写的程序做过这样的事情。

第二种方法的一些示例

所有这些都使用您作为数据发布的文件(下面是/tmp/engmath-sample.lisp)。

首先检查它是否可以用类似的功能读取

(defun read-file-naively (f)
;; Just read all the forms in a file and return a list of them
(with-open-file (in f)
(loop for form = (read in nil in)
until (eql form in)
collect form)))

这样一来,(read-file-naively "/tmp/engmath-sample.lisp")将返回一个相当长的列表。至关重要的是,它不会吐,所以这个文件,至少,Lisp是可读的。

以下是一些稍微伪造本体的代码:这刚好足以成功加载示例文件:

;;;;
;;;
(defpackage :fake-ontolingua
(:use :cl)
(:export
#:clear-theories
#:find-theory
#:theory-name #:theory-supers #:theory-issues
#:theory-documentation #:theory-relations
#:frame-ontology
#:define-theory
#:in-theory
#:current-theory
#:current-relations
#:find-relation
#:clear-relations
#:relation-name #:relation-theory #:relation-arglist
#:relation-documentation #:relation-body
#:define-relation))
(defpackage :fake-ontolingua-user
(:nicknames :ontolingua-user)
(:use :cl :fake-ontolingua))          ;should it use CL?
(in-package :fake-ontolingua)
(defvar *theories* (make-hash-table))
(defclass theory ()
((name :initarg :name
:reader theory-name)
(supers :initform '()
:reader theory-supers)
(issues :initform '()
:initarg :issues
:reader theory-issues)
(documentation :initform nil
:initarg :documentation
:reader theory-documentation)
(relations :initform '()
:accessor the-theory-relations)))
(defun find-theory (name &optional (errorp t))
(let ((it (gethash name *theories*)))
(or it
(if errorp
(error "no theory ~S" name)
nil))))
(defun (setf find-theory) (theory name)
(setf (gethash name *theories*) theory))
(defgeneric ensure-theory (theory-or-name)
(:method ((name symbol))
(find-theory name))
(:method ((theory theory))
theory)
(:method (mutant)
(error "what?")))
(defmethod initialize-instance :after ((theory theory)
&key (supers '(frame-ontology)))
(setf (slot-value theory 'supers)
(mapcar #'ensure-theory supers)))
(defvar *current-theory* nil)
(defun in-theory (theory-name)
(setf *current-theory* (find-theory theory-name)))
(defun current-theory ()
*current-theory*)
(defun clear-theories ()
;; Reset everything
(clrhash *theories*)
(setf (gethash 'frame-ontology *theories*)
(make-instance 'theory :name 'frame-ontology :supers '()))
(in-theory 'frame-ontology)
(values))
;;; Bootstrap theories
(clear-theories)
(defun make-theory (name kws)
(when (find-theory name nil)
(restart-case
(error "redefinition not supported")
(continue ()
:report "clear all existing theories"
(clear-theories)
(make-theory name kws))))
(setf (find-theory name) (apply #'make-instance 'theory :name name kws)))
(defmacro define-theory (name supers &body doc/body)
(let ((effective-body (if (stringp (first doc/body))
(cons ':documentation doc/body)
doc/body)))
`(progn
(make-theory ',name (list* ':supers ',supers ',effective-body))
',name)))
(defun clear-relations (&optional (theory *current-theory*))
(setf (the-theory-relations theory) nil)
(values))
(defgeneric theory-relations (theory)
;; Get them in the right order.  (Should use collecting to make
;; relation list...)
(:method ((theory theory))
(reverse (the-theory-relations theory))))
(defun current-relations (&optional (theory (current-theory)))
(theory-relations theory))
(defun find-relation (name &optional (theory (current-theory))
(errorp t))
(let ((it (assoc name (the-theory-relations theory))))
(cond
(it (cdr it))
(errorp (error "no relation ~A" name))
(t nil))))
(defclass relation ()
((name :initarg :name
:reader relation-name)
(theory :initarg :theory
:reader relation-theory)
(arglist :initarg :arglist
:reader relation-arglist)
(documentation :initarg :documentation
:initform nil
:reader relation-documentation)
(body :initarg :body
:reader relation-body)))
(defun make-relation (name kws)
(let* ((theory *current-theory*)
(relations (the-theory-relations theory))
(existing (assoc name relations))
(relation (apply #'make-instance 'relation
:name name
:theory theory
kws)))
(cond
(existing
(warn "redefining ~A in ~A" name (theory-name theory))
(setf (cdr existing) relation))
(t
(setf (the-theory-relations theory)
(acons name relation (the-theory-relations theory)))))
relation))
(defmacro define-relation (name arglist &body doc/body)
(let ((effective-body
(if (stringp (first doc/body))
(list ':documentation (first doc/body)
':body (rest doc/body))
(list ':body doc/body))))
`(progn
(make-relation ',name (list* ':arglist ',arglist ',effective-body))
',name)))

加载并编译后,您可以加载示例:

> (load (compile-file "fake-ontolingua"))
[noise from compiler removed]
> (in-package :ontolingua-user)
#<The FAKE-ONTOLINGUA-USER package, 0/16 internal, 0/16 external>
> (load "engmath-sample.lisp")
; Loading text file /private/tmp/engmath-sample.lisp
#P"/private/tmp/engmath-sample.lisp"
> (find-relation 'linear-space)
#<fake-ontolingua::relation 40200B6323>
ONTOLINGUA-USER 6 > (relation-body (find-relation 'linear-space))
(:iff-def
[lots of stuff]) 

请注意,此代码仅足以读取示例文件并从中构建结构。这个结构不是本体,尤其是这个东西对什么是关系、关系体是什么或诸如此类的东西一无所知。要想真正做任何有用的事情,你需要充分了解KIF/Ontolingua,以理解事物的含义,然后编写一个程序,该程序可以遍历所有关系并吐出合适的OWL。

最新更新