我有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代码插件。但我不知道如何解决它
1条答案
按热度按时间bf1o4zei1#
您还没有告诉我们您所说的“构建”项目是什么意思(您说它是成功的),然后“运行”项目。您报告的错误显然是一个编译时错误,而不是在运行已经生成的代码时可能收到的错误。但是,对于必须首先重新编译代码的“运行”,有几种可能的含义(例如,将Haskell文件加载到
ghci
中,然后键入Haskell命令来处理您的代码,或者在Haskell文件上使用runhaskell
,将您的代码作为shell命令执行)。正如chi在评论中提到的,像
import Data.Base
这样的导入将在名为Data
的目录 * 中查找文件Base.hs
*。在存放这些文件的地方,实际上应该有一个名为Data
的文件夹,其中应该有Base.hs
和Entities.hs
。但是,如果您已经有了这个文件夹,然后您进入您的文件所在的文件夹(
Data
文件夹),然后键入ghci Entities.hs
或runhaskell Entities.hs
(或任何类似的内容),您仍然会得到错误!(我猜“当我运行一个项目”时,你是指进入ghci
这是因为编译器无法读取你的想法,知道你认为哪个文件夹是源代码树的“根”。
编译器如何知道文件
Base.hs
在Haskell模块空间中应该被“寻址”为Data.Base
呢?它也可以只是Base
,或者ThisProject.Data.Base
或CodingStuff.ThisProject.Base
。因此,当您简单地告诉它运行一个没有其他配置的文件时,它所做的是将工作目录视为“根”。所以要运行Entities.hs
,你需要在Data
文件夹上面的文件夹中,而不是在实际上有两个文件的文件夹中。然后你可以简单地运行ghci Data/Entities.hs
(或ghci Data.Entities
),它就会工作。Haskell开发人员解决这个问题的常规方法是使用
.cabal
文件将他们的代码制作成正式的package 1(如果使用堆栈,则为package.yaml
文件)。然后cabal
(或stack)使用这个文件的内容来告诉它源代码树的根位置以及存在哪些模块,因此您可以cabal repl
来启动一个解释器会话2,或者,如果你的项目是一个可执行文件,并且你正在构建你的项目(你说它是成功的),为什么你不运行构建好的可执行文件呢?如果你使用ghci
或runhaskell
,你每次运行它的时候都要 * 再次 * 编译它,而且可能没有太多的优化。如果你不想学习Haskell软件包的工作原理(和
cabal
这样的工具),如果你的项目只是一些不需要任何库的文件,那么这可能是完全合理的。在这种情况下,我建议你在模块名称中去掉Data.
前缀。只需将它们命名为module Base
和module Entities
,并将它们放在同一个文件夹中,而且你可以从那个文件夹中ghci
,没有任何复杂性。如果你的项目变得足够大,以至于你真的想使用文件夹来组织你的文件,或者如果你需要安装任何外部库,那么你真的应该学习打包工具。这看起来会让人望而生畏,但老实说,这是 * 方式 * 学习cabal
比学习如何处理不使用软件包会遇到的所有问题更少麻烦。老实说对于你所展示的文件,我无论如何都会放弃
Data
前缀。我想你使用它是因为你已经看到了很多以Data
开头的模块,并且假设他们这样做是有原因的,所以你也应该这样做。但是Data
是一个 * 非常 * 通用的名称空间,里面有 * 很多 。在我看来,它真的应该““最终用户”代码不会使用太多,应该留给将在Hackage上发布的广泛适用的库。否则, 所有 * 都将以Data
结束,如果所有都在同一个名称空间中,您可能根本没有使用该名称空间。特别是,前缀Data
在许多库中使用得非常广泛,因此您绝对不应该直接在Data
名称空间下使用高度通用的名称,如Base
和Entities
。如果这些模块是特定于您的项目的,那么如果这是一个库,您可能只需要使用一个从项目名称派生的前缀,或者如果这些模块是可执行文件的一部分,甚至可以根本不使用前缀。(可执行文件不能被导入到 other 项目中,所以他们不需要担心选择在其他上下文中描述性的名称,这些名称与未知的其他库放在一起。模块名称只需要在这个特定项目的上下文中标识它们,在这里你知道所有其他的东西,所以你知道你可能会混淆什么。这意味着使用前缀-更少的名称,使您的“本地”模块在您导入的所有其他模块中更容易识别,因为它们不以
Data
或Control
或其他常见前缀开头。对于库中的非公开模块也是如此)1您提到VS Code;它可能已经为您做了这件事,如果没有的话,它几乎肯定有一个简单的选项来做这件事。但是我从来没有在Haskell中使用过VS Code(而且很多年都没有使用过),所以我不知道它是如何工作的。
2或者一个等价的stack命令。Stack和cabal都是用来管理Haskell项目的工具。你可以使用你喜欢的任何一个。从现在开始,我不再在我所说的关于cabal的每一句话中加上“or stack”。