haskell 找不到模块,如何解决此问题?

gmxoilav  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(199)

我有2个文件Base.hs和Entities.hs。这些文件在同一个文件夹中。和Base导入实体。
Base.hs:

module Data.Base (Color(..)) where

data Color = White | Black | Other
    deriving (Show)

Entities.hs:

module Data.Entities (Product(..), Shop(..), Order(..), Customer(..), productID, productName, productPrice, productColor) where

import Data.Base (Color(..))

type ProductID = Int
type ProductName = String
type ProductPrice = Double
type ProductColor = Color

data Product = Product ProductID ProductName ProductPrice ProductColor
    deriving (Show)

productID :: Product -> ProductID
productID (Product pid _ _ _) = pid

productName :: Product -> ProductName
productName (Product _ name _ _) = name

productPrice :: Product -> ProductPrice
productPrice (Product _ _ price _) = price

productColor :: Product -> ProductColor
productColor (Product _ _ _ color) = color

data Shop = Shop {
      shopID :: Int
    , shopName :: String
    , shopAddress :: String
} deriving (Show)

data Customer = Customer {
      customerID :: Int
    , customerName :: String
    , customerAddress :: String  
} deriving (Show)

data Order = Order {
      orderID :: Int
    , orderNumber :: String 
} deriving (Show)

当我运行一个项目时,我在Entities.hs中出现错误:

Could not find module `Data.Base'
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
3 | import Data.Base (Color(..))

  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我的项目结构:

└── Project
    └── src
        └── Data
            ├── Base.hs
            └── Entities.hs

如何修正这个错误?
项目的建设是成功的,所以错误可能会出来,因为一些vs代码插件。但我不知道如何解决它

bf1o4zei

bf1o4zei1#

您还没有告诉我们您所说的“构建”项目是什么意思(您说它是成功的),然后“运行”项目。您报告的错误显然是一个编译时错误,而不是在运行已经生成的代码时可能收到的错误。但是,对于必须首先重新编译代码的“运行”,有几种可能的含义(例如,将Haskell文件加载到ghci中,然后键入Haskell命令来处理您的代码,或者在Haskell文件上使用runhaskell,将您的代码作为shell命令执行)。
正如chi在评论中提到的,像import Data.Base这样的导入将在名为Data的目录 * 中查找文件Base.hs *。在存放这些文件的地方,实际上应该有一个名为Data的文件夹,其中应该有Base.hsEntities.hs

但是,如果您已经有了这个文件夹,然后您进入您的文件所在的文件夹(Data文件夹),然后键入ghci Entities.hsrunhaskell Entities.hs(或任何类似的内容),您仍然会得到错误!

(我猜“当我运行一个项目”时,你是指进入ghci
这是因为编译器无法读取你的想法,知道你认为哪个文件夹是源代码树的“根”。

.
└── CodingStuff
    └── ThisProject
        └── Data
            ├── Base.hs
            └── Entities.hs

编译器如何知道文件Base.hs在Haskell模块空间中应该被“寻址”为Data.Base呢?它也可以只是Base,或者ThisProject.Data.BaseCodingStuff.ThisProject.Base。因此,当您简单地告诉它运行一个没有其他配置的文件时,它所做的是将工作目录视为“根”。所以要运行Entities.hs,你需要在Data文件夹上面的文件夹中,而不是在实际上有两个文件的文件夹中。然后你可以简单地运行ghci Data/Entities.hs(或ghci Data.Entities),它就会工作。
Haskell开发人员解决这个问题的常规方法是使用.cabal文件将他们的代码制作成正式的package 1(如果使用堆栈,则为package.yaml文件)。然后cabal(或stack)使用这个文件的内容来告诉它源代码树的根位置以及存在哪些模块,因此您可以cabal repl来启动一个解释器会话2,或者,如果你的项目是一个可执行文件,并且你正在构建你的项目(你说它是成功的),为什么你不运行构建好的可执行文件呢?如果你使用ghcirunhaskell,你每次运行它的时候都要 * 再次 * 编译它,而且可能没有太多的优化。
如果你不想学习Haskell软件包的工作原理(和cabal这样的工具),如果你的项目只是一些不需要任何库的文件,那么这可能是完全合理的。在这种情况下,我建议你在模块名称中去掉Data.前缀。只需将它们命名为module Basemodule Entities,并将它们放在同一个文件夹中,而且你可以从那个文件夹中ghci,没有任何复杂性。如果你的项目变得足够大,以至于你真的想使用文件夹来组织你的文件,或者如果你需要安装任何外部库,那么你真的应该学习打包工具。这看起来会让人望而生畏,但老实说,这是 * 方式 * 学习cabal比学习如何处理不使用软件包会遇到的所有问题更少麻烦。
老实说对于你所展示的文件,我无论如何都会放弃Data前缀。我想你使用它是因为你已经看到了很多以Data开头的模块,并且假设他们这样做是有原因的,所以你也应该这样做。但是Data是一个 * 非常 * 通用的名称空间,里面有 * 很多 。在我看来,它真的应该““最终用户”代码不会使用太多,应该留给将在Hackage上发布的广泛适用的库。否则, 所有 * 都将以Data结束,如果所有都在同一个名称空间中,您可能根本没有使用该名称空间。特别是,前缀Data在许多库中使用得非常广泛,因此您绝对不应该直接在Data名称空间下使用高度通用的名称,如BaseEntities。如果这些模块是特定于您的项目的,那么如果这是一个库,您可能只需要使用一个从项目名称派生的前缀,或者如果这些模块是可执行文件的一部分,甚至可以根本不使用前缀。

(可执行文件不能被导入到 other 项目中,所以他们不需要担心选择在其他上下文中描述性的名称,这些名称与未知的其他库放在一起。模块名称只需要在这个特定项目的上下文中标识它们,在这里你知道所有其他的东西,所以你知道你可能会混淆什么。这意味着使用前缀-更少的名称,使您的“本地”模块在您导入的所有其他模块中更容易识别,因为它们DataControl或其他常见前缀开头。对于库中的非公开模块也是如此)
1您提到VS Code;它可能已经为您做了这件事,如果没有的话,它几乎肯定有一个简单的选项来做这件事。但是我从来没有在Haskell中使用过VS Code(而且很多年都没有使用过),所以我不知道它是如何工作的。
2或者一个等价的stack命令。Stack和cabal都是用来管理Haskell项目的工具。你可以使用你喜欢的任何一个。从现在开始,我不再在我所说的关于cabal的每一句话中加上“or stack”。

相关问题