【问题标题】:Load a module in GHCi by module name when module name doesn't match file name当模块名称与文件名不匹配时,按模块名称在 GHCi 中加载模块
【发布时间】:2015-01-28 13:18:17
【问题描述】:

假设我有一个名为MyModule.hs 的源文件,其中的模块声明是module My.Module where ...(注意:不是 module MyModule where ...)。

我无权更改此源文件或更改文件所在的目录结构。

从阅读some docs about importing modules in GHCi 来看,似乎有一些方法可以按文件名 导入(例如import:load),但没有任何方法可以指定将在本地目录的所有文件中搜索。

有没有办法在 GHCi 中导入 My.Module 而无需通过指定文件名(仅模块名称)而不安装它(例如,不使用 cabal 构建它,只需按模块快速将其扔进 GHCi名字)?

【问题讨论】:

    标签: haskell import module ghci


    【解决方案1】:

    根据documentation,您不能在名称中包含一个点

    对于这些目录中的每一个,它都会尝试将 basename.extension 附加到目录中,并检查文件是否存在。 basename 的值是模块名,用点替换为目录分隔符('/' 或 '\',取决于系统),而 extension 是源扩展名(hs、lhs)...

    关键部分是

    basename 的值是模块名称,用点替换为目录分隔符('/' 或 '\',取决于系统)

    因此您的模块名称My.Module 将被搜索为My/Module.hs。你需要有一个像

    这样的目录结构
    project/
        My/
            Module.hs
        project.cabal
    

    你可以从文件夹project 运行

    $ cabal repl
    GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking ... done.
    Loading package base ... linking ... done.
    > import My.Module
    

    如果您的文件名为MyModule.hs 并且您的模块名称为MyModule,您可以执行此操作,但这只是上述规则的一个特例。

    这样做有充分的理由,即它强制执行一种结构来简化您的项目结构和 GHC 的搜索算法。如果没有这个规则,什么会阻止我拥有

    project/
        MyModule1.hs
        MyModule2.hs
    

    两个.hs 文件在哪里都有模块声明My.Module?如果我运行import My.Module,在 GHCi 中加载哪个是正确的?通过指定文件名和路径,您立即知道模块X.Y.Z.W.Q.R.S.T 位于路径X/Y/Z/W/Q/R/S/T.hs,无需搜索。它减少了松散的模块名称规范可能出现的很多歧义。

    【讨论】:

    • 在您给出的最后一个示例中,我认为哪个是要加载的正确模块的问题是微不足道的:无论是在搜索路径上还是在搜索顺序中首先找到的那个。这就是在许多其他语言中解决此问题的方式。我并不是说这是赞成或反对 w.r.t。你的答案——只是我认为这是一个微不足道的问题,并认为允许人们在他们喜欢的情况下重复使用相同的模块名称对我来说似乎很好。阻止它并不能真正“保护”你免受任何伤害。
    • 另外,关于这一切的文档表明,在 Haskell 中做很多事情是完全有效和合理的:每个文件定义多个模块是可以的;在多个文件中定义一个模块是可以的(通过重复使用相同的模块名称并确保没有声明的名称冲突);并将模块命名为与文件名不同的名称也可以(您仍然可以将其作为包导入,或者在 GHCi 中使用文件名导入)。所有这些都列在我在问题中链接的文档中。因此,虽然将模块映射到文件路径可能是常见做法,但语言肯定不会强制执行。
    • @prpl.mnky.dshwshr 如果你只使用路径上找到的第一个,你使用什么排序方法? Unicode 排序?好的,所以现在其中一个总是被加载而另一个没有,那么你如何加载第二个模块?另外,我知道没有一种语言能真正做到你所说的。在 .NET 语言中你不能,尽管文件名与模块结构无关。在 Python 中,文件名就是模块名,你不需要声明你的模块名。
    • @prpl.mnky.dshwshr 您链接到的文档中的示例实际上仅适用于Main 模块并使用:load 命令。事实上,该文档指出“问题:GHC 如何找到包含模块 M 的文件名?答案:它查找文件 M.hs 或 M.lhs。这意味着对于大多数模块,模块名称必须匹配文件名。如果不匹配,GHCi 将无法找到它。"(强调我的)。
    • "这个一般规则有一个例外:当你用 :load 加载程序时,或者在调用 ghci 时指定它,你可以给出一个文件名而不是模块名。这个文件名被加载如果它存在,并且它可能包含您喜欢的任何模块。如果您在同一目录中有多个 Main 模块并且您不能将它们都称为 Main.hs,这将特别方便。 - 例外是在 GHCi 中,您可以专门在文件名上使用 :load,但这是 GHCi 中的一个实现功能,它不是 Haskell 语言的一部分。 Haskell 语言指定了一个文件结构。
    猜你喜欢
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2018-07-07
    相关资源
    最近更新 更多