将“EngMath”(数学本体)从 lisp 转换为 OWL
Posted
技术标签:
【中文标题】将“EngMath”(数学本体)从 lisp 转换为 OWL【英文标题】:Convert "EngMath" (Ontology for Mathematics) from lisp to OWL 【发布时间】:2021-05-30 08:53:12 【问题描述】:早在 OWL 规范之前的 1994 年,Thomas R. Gruber 和 Gregory R. Olsen 发表了An Ontology for Engineering Mathematics。由于缺乏任何特定于本体的语言,它是在 lisp 中实现的。 lisp 代码仍然可用(参见 example),但不能被现代 OWL 本体使用(也称为导入)。
使这个本体可用于当今(基于 OWL)的工具链的最简单方法是什么?
【问题讨论】:
这是在 Lisp 中实现的。它是 Lisp 之上的一种特定于本体的语言。一种所谓的嵌入式领域特定语言。您可能需要阅读文档和源代码,因为它被明确设计为可以转换为其他语言。 这相当于一个封闭的(然后被作者删除了!)previous question asked a week ago by the same person。 事实上在原始问题结束后,我对其进行了编辑以符合指南。然后,它很快就重新获得了两票(但三票是必要的)。我对此事的解释:编辑后的版本很好,但缺乏吸引最终重新投票的注意力。当前的表述与编辑版本相同,而不是原始版本,后者显然不够专注,因此吸引了三票。 我认为这个问题有合理的答案,不应该关闭。第二天我正在睡觉/忙碌,但会尝试发布一个。 (免责声明:我对原版投了重新开放投票之一)。 【参考方案1】:有两种可能的方法来解决这个问题:你想采用哪一种,部分取决于编写这个本体的系统是否仍然可以访问。这些方法对于拯救其他用 Lisp 编写的旧包很常见,所以我认为它们值得一提。
这个答案没有给出如何做到这一点的详细说明,因为这个过程在一定程度上是迭代和实验性的。
软件是如何开发的(在 Lisp 中)
经常让人们感到困惑的一件事是,这个系统根本没有真正在 Lisp 中实现。
用计算机解决问题的一个非常好的方法是首先实现一种易于讨论问题领域的语言。这是一种极其常见的方法:大量的大型系统涉及一种或多种专用语言。例如,驱动现代系统的所有小型配置文件格式实际上都是小型专用语言。任何曾经在大型软件系统上工作过的人都会遇到大量这样的事情。
而且它们中的大多数会很糟糕,因为它们是由不知道自己在做什么的人编写的:他们不明白自己在设计一种语言,而是认为自己在做其他事情,通常涉及替换字符串与其他基于模式的字符串。
Lisp 是少数几个对此开放的语言家族之一:在 Lisp 中解决问题的方式非常明确,是通过编写一种可以更好地表示问题的语言。该语言(通常)在表面上看起来有点像 Lisp:它将使用带括号的前缀符号等,但它还将包含根本不存在于底层 Lisp 中的结构。 (事实上,现代 Lisps 它们自己就是这样的语言:它们是以更简单的版本实现的语言。)
因此,EngMath 系统是用一种在 Lisp 之上实现的语言编写的程序:它根本不是真正用 Lisp 编写的。该语言是 KIF 或 Ontolingua:我不明白这两者之间的关系。
第一步:拥有一个Common Lisp环境
所有这一切的第一步是拥有一个优质的 Common Lisp 环境,并在一定程度上熟悉它的使用。我不会在这里推荐一个,因为我对此非常陌生,但有几个是免费提供的。
如果底层本体语言仍然可用
因此,拯救系统的第一种方法是在底层语言的实现仍然有用的情况下使用。如果是这种情况,我无法确定:Stanford KSL 网站上的许多链接现在似乎没有指向任何地方,因此它可能存在也可能不存在。正如我上面所说,我认为底层语言要么是 KIF,要么是 Ontolingua(可能 Ontolingua 是 KIF 的实现?不确定)。
那么方法如下。
-
获取底层本体语言以在您的 Lisp 中构建。这可能很难,也可能不难:Common Lisp 一直非常稳定,但一些旧程序在该语言的临时版本中编写得非常草率,并且取决于具体的实现特性。
让您的本体以这种重构的语言加载。
用重构的语言对其进行测试。
充分了解本体对应的对象的实现,可以进行下一步。这将涉及阅读和试验底层本体语言的源代码。
编写一个程序(在本地 Lisp 和底层本体语言的某种组合中),它可以遍历与本体相对应的对象并以您想要的某种格式打印它们(可能是 OWL?)
利润。
这将是大量的工作。请注意,如果您只想使用本体,则可以从上面的步骤(3)分支:一旦系统运行,您就可以使用本体。
如果底层本体语言仍然不可用
如果基础语言变得有效或真的不可用,您可以使用这种方法。它也可能是一种更好的方法,即使它 仍然可用,如果 all 您想要做的是转换。
-
了解底层语言中数据的表面表示是什么。如果语言是 KIF,则至少有 some papers 幸存,这可能会对您有所帮助。
说服 Lisp 阅读本体源。这可能并不像看起来那么难:看起来您发布链接到的本体部分似乎没有使用任何特别奇怪的读取级别语法。有关这方面的更多信息,请参见下文。
编写一个假垫片,允许 Lisp 构造对应于本体的假对象。这也应该相当简单:见下文。
一旦有了这些伪造的对象,就可以处理它们以发出合适的 OWL 输出。这需要对旧的本体语言有足够的了解,以便能够将用它编写的东西变成 OWL。
利润。
这种方法仍然很痛苦,但它可能不如第一种痛苦:如果原始系统丢失,这也是你所能做的。我用古老的(非常古老的)代数系统编写的程序做过类似的事情。
第二种方法的一些例子
所有这些都使用file you posted 作为数据(下面是/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 的程序。
【讨论】:
基于这个答案,我找到了以下参考:Formalizing Knowledge by Ontologies: OWL and KIF。它指出 Ontolingua “是一种基于 KIF 的语言”。 @cknoll:是的,我认为应该可以从 KIF 规范中弄清楚这些东西的含义,即使 Ontolingua 不存在,它仍然存在。以上是关于将“EngMath”(数学本体)从 lisp 转换为 OWL的主要内容,如果未能解决你的问题,请参考以下文章
在 Common Lisp 中将 FUNCTION 转换为 STRING 或 SYMBOL
如何将字符串转换为符号以用作 Lisp“assoc”函数中的键?