指定"向上树"Haskell模块

Xop*_*ter 5 haskell module hierarchy

我的理解是,Haskell中模块的虚线语法表示磁盘上的逻辑结构.所以,如果我们有这样的结构:

Main.hs
Foo/
  Bar.hs    -- exports "Bar"
  Quux.hs   -- exports "Quux"
Run Code Online (Sandbox Code Playgroud)

...然后在我们的Main.hs,我们可以做:

import Foo.Bar
import Foo.Quux
Run Code Online (Sandbox Code Playgroud)

(我假设我们只能在文件系统的叶节点上有模块.例如,在上面,我们也无法拥有Foo模块.)

在这个例子中,我们正在遍历树.如果我们想上去怎么办?

lib/
  SomeModule.hs
  XYZ.hs
src/
  Main.hs
Run Code Online (Sandbox Code Playgroud)

那就是,Main.hs我们如何进口SomeModuleXYZ

也许这不会是常见现象Main,但是模块间的依赖关系呢?他们可以合法地需要引用"堂兄"节点.

Mik*_*kov 7

只需使用模块的完全限定名称,并告诉GHC在哪里可以找到带有该-i选项的模块层次结构的根.在您的示例中,这意味着您应该使用import XYZin Main.hs来导入模块和命令ghc -i../src --make Main.hs来编译程序.如果需要编译相互递归的模块,请查看GHC手册的这一部分.

如果您使用Cabal构建程序包,则可以lib将库中的模块分组,然后使该库成为可执行文件的依赖项.您将具有以下目录结构:

some-package.cabal
lib/
  XYZ.hs
src/
  Main.hs
Run Code Online (Sandbox Code Playgroud)

some-package.cabal文件的相关部分如下所示:

Name: some-package
Version: 1.0
...
Library
    ...
    Exposed-modules: XYZ
    Hs-source-dirs:  lib
    ...
Executable some-executable
    ...
    build-depends: some-package == 1.0
    ...
...
Run Code Online (Sandbox Code Playgroud)

如果您的软件包包含测试或基准测试套件,这将特别有用,因为下面的模块lib将只编译一次.

这是这种技术的现实例子.