在Common Lisp中,路径名与操作系统无关。

问题描述 投票:0回答:1

我想加载一个位于当前工作文件夹子目录中的lisp脚本。相对路径是 .crossover-operatorsER.lisp.

在Linux中是通过以下方式完成的。

(load "./crossover-operators/ER.lisp")

在Windows中是由:

(load ".\\crossover-operators\\ER.lisp")

我怎样才能让一个函数加载 ER.lisp 脚本独立于我的通用Lisp脚本运行的操作系统?

filesystems clisp
1个回答
5
投票

首先 19.1.1 作为文件名的名称字符串 说,的确,namestring(字符串作为路径名)是不可移植的。

一个符合要求的程序绝对不能无条件地使用除逻辑路径名namestring以外的字面namestring,因为除了逻辑路径名的namestring之外,Common Lisp没有定义任何可以保证可移植的namestring语法。

还要注意的是,如果你向用户索取文件名,你可以可移植地使用它们。

然而,一个符合要求的程序,如果它很小心,可以成功地操作用户提供的包含或引用不可移植的名字串的数据。

你有两个选择,它们并不排斥彼此:使用路径名构造器,或者使用逻辑路径名。

路径名构造器

构建路径名时使用 make-pathname, merge-pathnames. 路径名是一个由不同组件(目录、名称、类型等)组成的结构,它们可以组合在一起。它们是由一个 原型继承 方法,即通过复制一个现有的路径并改变其中的一些组件来创建新的路径名。

make-pathname 就像一个结构体构造函数一样,只是它有一个 :defaults 参数,给出一个路径名作为原型。

merge-pathnames 是有点不同的,因为它还执行语义操作。

例如,如果 *default-pathname-defaults*,存放默认路径名的特殊变量,设置如下。

USER> (setf *default-pathname-defaults*
            (make-pathname :directory '(:relative "crossover-operator")))
#P"crossover-operator/"

那么你有两种不同的行为

USER> (make-pathname :directory '(:relative "tmp")  
                     :defaults *default-pathname-defaults*)
#P"tmp/"

make-pathname 替换原始路径名的目录组件。

USER> (merge-pathnames *)
#P"crossover-operator/tmp/"

merge-pathnames 取一个路径名(这里是我们刚刚建立的路径名,用以下方式表示 *),并将该目录相对合并到了 *default-pathname-defaults*.

逻辑路径名

逻辑路径名有点像URL(统一资源定位器),只是间接表示文件。程序员必须定义 翻译功能 从逻辑路径名到实际的物理路径名,基于的是 HOST 地址的一部分。

路径名的印刷表示(namestrings),是不可移植的。除了 的逻辑路径名。参见 19.3.1 逻辑路径名字符串的语法.

除了具有定义的语法和转换功能(从逻辑路径名到物理路径名)之外,它们的行为就像其他路径名一样,所以你可以调用 merge-pathnames 如上图所示。

路径名翻译可以映射到非可移植的名称串(但你可以在不同的主机上设置不同的翻译),也可以映射到逻辑或物理路径名。超规格的 LOGICAL-PATHNAME-TRANSLATIONS 有一些关于如何使用逻辑路径名的例子,比如这个。

 ;;;A more complex example, dividing the files among two file servers
 ;;;and several different directories.  This Unix doesn't support
 ;;;:WILD-INFERIORS in the directory, so each directory level must
 ;;;be translated individually.  No file name or type translations
 ;;;are required except for .MAIL to .MBX.
 ;;;The namestring syntax on the right-hand side is implementation-dependent.
 (setf (logical-pathname-translations "prog")
       '(("RELEASED;*.*.*"        "MY-UNIX:/sys/bin/my-prog/")
         ("RELEASED;*;*.*.*"      "MY-UNIX:/sys/bin/my-prog/*/")
         ("EXPERIMENTAL;*.*.*"    "MY-UNIX:/usr/Joe/development/prog/")
         ("EXPERIMENTAL;DOCUMENTATION;*.*.*"
                                  "MY-VAX:SYS$DISK:[JOE.DOC]")
         ("EXPERIMENTAL;*;*.*.*"  "MY-UNIX:/usr/Joe/development/prog/*/")
         ("MAIL;**;*.MAIL"        "MY-VAX:SYS$DISK:[JOE.MAIL.PROG...]*.MBX")))

 ;;;Sample use of that logical pathname.  The return value
 ;;;is implementation-dependent.          
 (translate-logical-pathname "prog:mail;save;ideas.mail.3")
=>  #P"MY-VAX:SYS$DISK:[JOE.MAIL.PROG.SAVE]IDEAS.MBX.3"

2
投票

根据@coredump的回答和其他研究,一个快速的答案是:

(load (make-pathname :name "ER"
                     :type "lisp"
                     :defaults (make-pathname :directory '(:relative "crossover-operators"))))
© www.soinside.com 2019 - 2024. All rights reserved.