【问题标题】:Pathname independent of operating system in Common LispCommon Lisp 中独立于操作系统的路径名
【发布时间】:2020-05-22 15:48:02
【问题描述】:

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

在 Linux 中,这是通过以下方式完成的:

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

在 Windows 中由以下人员完成:

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

如何创建一个函数来独立于运行我的 Common Lisp 脚本的操作系统来加载 ER.lisp 脚本?

【问题讨论】:

    标签: filesystems lisp common-lisp


    【解决方案1】:

    首先,19.1.1 Namestrings as Filenames 说,namestring(作为路径名的字符串)确实不可移植。

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

    另请注意,如果您向用户询问文件名,您可以便携地使用它们:

    但是,如果小心,符合标准的程序可以成功地操作包含或引用不可移植名称字符串的用户提供的数据。

    您有两个选项,它们并不互斥:使用路径名构造函数,和/或使用逻辑路径名。

    路径名构造函数

    使用make-pathnamemerge-pathnames 构建路径名。路径名是具有不同组件(目录、名称、类型等)的结构,它们可以组合在一起。它们是使用prototypal inheritance 方法构建的,您可以通过复制现有路径名并更改其某些组件来创建新路径名。

    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 部分定义从逻辑路径名到实际物理路径名的翻译函数

    路径名(名称字符串)的打印表示是不可移植的,除了逻辑路径名。见19.3.1 Syntax of Logical Pathname Namestrings

    除了具有定义的语法和翻译功能(从逻辑路径名到物理路径名)外,它们的行为与其他路径名一样,因此您可以调用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"))))
      

      【讨论】:

      • 是的。请注意,路径是相对的,因此实际位置取决于尝试打开文件时绑定的 default-pathname-defaults 值,通常这与您正在加载的文件等无关。不要犹豫,询问更多提问是否有问题。
      • 谢谢。我查看了路径名对象的组件(主机、设备、目录、名称、类型和版本),但实际上我并不理解它们的所有含义和目的。具体不知道“主机”、“设备”和“类型”组件是什么。
      猜你喜欢
      • 2020-05-17
      • 1970-01-01
      • 2020-02-02
      • 1970-01-01
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多